home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- article.c
-
- This module handles article windows.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
-
- #include <Icons.h>
-
- #include "glob.h"
- #include "article.h"
- #include "child.h"
- #include "newswatcher.h"
- #include "dialog.h"
- #include "header.h"
- #include "mark.h"
- #include "news.h"
- #include "menus.h"
- #include "datetime.h"
- #include "print.h"
- #include "next.h"
- #include "message.h"
- #include "cancel.h"
- #include "status.h"
- #include "strutil.h"
- #include "tescroll.h"
- #include "url.h"
- #include "drawutil.h"
- #include "memutil.h"
- #include "windutil.h"
- #include "teutil.h"
- #include "wind.h"
- #include "fileutil.h"
- #include "sfutil.h"
- #include "iconutil.h"
- #include "apputil.h"
- #include "dragutil.h"
- #include "subject.h"
- #include "group.h"
- #include "key.h"
- #include "search.h"
- #include "ic.h"
- #include "help.h"
- #include "arrowpair.h"
-
-
-
- #define kMinWindowWidth 400 /* minimum window width */
- #define kSectionMargin 165 /* right coord of "Section x of y" rect */
-
- #define kArticleFileExistsAlert 144
- #define kTooStupidAlert 152
-
- #define kFileIconID 203
-
- #define kMaxCachedArticles 50 /* max number of cached articles */
- #define kArticleCacheMemoryToKeepFree 150000L /* amount of memory to keep free when
- caching articles */
-
-
-
- typedef struct TCachedArticleInfo {
- unsigned long timeCached; /* tickcount when entry added to cache */
- Handle groupName; /* handle to group name, or nil if by id */
- long number; /* article number in group if not by id */
- Handle msgId; /* handle to message id if by id */
- Handle txt; /* handle to full article text (purgable!) */
- Boolean inUse; /* true if this cache entry is being used */
- Boolean flagReqd; /* true if when fetched from server BinHex or uuencode
- text was required to have a special "begin" flag line */
- Boolean attachedFile; /* true if article contains an attached file */
- } TCachedArticleInfo;
-
-
-
- static TCachedArticleInfo **gArticleCache = nil; /* handle to article cache array */
-
- static TEClickLoopUPP gAutoScrollUPP;
- static DragSendDataUPP gDragAttachedFileIconSendProcUPP;
- static ControlActionUPP gScrollActionUPP;
- static ControlActionUPP gScrollActionSectionUPP;
-
-
-
- /*----------------------------------------------------------------------------
- SaveArticleInCache
-
- Save an article in the article cache.
-
- Entry: wind = pointer to article window.
-
- When an article window is closed or reused, instead of disposing the article
- text, we cache it in purgable memory in case the user reopens the article
- in the near future (e.g., via the up arrow control in an article window).
-
- This function transfers ownership of the full article text relocatable block
- from the article window to the cache, and the block is made purgable.
- Similarly, ownership of the two relocatable blocks containing the article
- message id and/or group name are transfered from the window to the cache,
- but these blocks are not made purgable.
- ----------------------------------------------------------------------------*/
-
- static void SaveArticleInCache (WindowPtr wind)
- {
- TWindow **info;
- OSErr err = noErr;
- short i, oldestTimeCachedIndex;
- Handle groupName, msgId, txt;
- unsigned long oldestTimeCached;
- TCachedArticleInfo *p;
-
- info = (TWindow**)GetWRefCon(wind);
-
- /* Do some sanity checks. */
-
- if ((**info).fullText == nil) goto exit;
- if ((**info).msgId == nil && (**info).groupName == nil) goto exit;
-
- /* Allocate the cache info array on the first call. */
-
- if (gArticleCache == nil) {
- err = MyNewHandle(kMaxCachedArticles * sizeof(TCachedArticleInfo), &gArticleCache);
- if (err != noErr) goto exit;
- }
-
- /* Search the cache to find either an available unused slot or the oldest used slot.
- Treat any used slots with purged text as unused. */
-
- oldestTimeCached = 0xffffffff;
- oldestTimeCachedIndex = -1;
- for (i = 0, p = *gArticleCache; i < kMaxCachedArticles; i++, p++) {
- if (p->inUse && *p->txt != nil) {
- if (p->timeCached < oldestTimeCached) {
- oldestTimeCached = p->timeCached;
- oldestTimeCachedIndex = i;
- }
- } else {
- break;
- }
- }
- if (i >= kMaxCachedArticles) i = oldestTimeCachedIndex;
-
- /* Dispose any old entry which occupies the slot. */
-
- p = *gArticleCache + i;
- if (p->inUse) {
- groupName = p->groupName;
- msgId = p->msgId;
- txt = p->txt;
- MyDisposeHandle(groupName);
- MyDisposeHandle(msgId);
- MyDisposeHandle(txt);
- }
-
- /* Cache the article at slot "i" in the cache info array. Make the
- article text purgable. */
-
- p = *gArticleCache + i;
- p->timeCached = TickCount();
- p->groupName = (**info).groupName;
- p->number = (**info).number;
- p->msgId = (**info).msgId;
- p->txt = (**info).fullText;
- p->inUse = true;
- p->flagReqd = (**info).flagReqd;
- p->attachedFile = (**info).attachedFile;
- (**info).groupName = nil;
- (**info).msgId = nil;
- (**info).fullText = nil;
- HPurge(p->txt);
-
- /* If we're getting low on free memory, purge the oldest cache entries.
- This helps prevent filling up all the free memory with cached articles,
- which would make the Memory Manager thrash around purging blocks all
- the time (and most likely purging the wrong ones at that. */
-
- while (FreeMem() < kArticleCacheMemoryToKeepFree) {
- oldestTimeCached = 0xffffffff;
- oldestTimeCachedIndex = -1;
- for (i = 0, p = *gArticleCache; i < kMaxCachedArticles; i++, p++) {
- if (p->inUse && p->timeCached < oldestTimeCached) {
- oldestTimeCached = p->timeCached;
- oldestTimeCachedIndex = i;
- }
- }
- if (oldestTimeCachedIndex < 0) break;
- p = *gArticleCache + oldestTimeCachedIndex;
- groupName = p->groupName;
- msgId = p->msgId;
- txt = p->txt;
- p->inUse = false;
- MyDisposeHandle(groupName);
- MyDisposeHandle(msgId);
- MyDisposeHandle(txt);
- }
-
- return;
-
- exit:
-
- MyDisposeHandle((**info).fullText);
- (**info).fullText = nil;
- MyDisposeHandle((**info).msgId);
- (**info).msgId = nil;
- MyDisposeHandle((**info).groupName);
- (**info).groupName = nil;
- }
-
-
-
- /*----------------------------------------------------------------------------
- GetArticleFromCache
-
- Get an article from the article cache.
-
- Entry: groupName = name of group, or nil if fetching by message id.
- number = article number. Ignored if fetching by message id.
- id = message id string, including < and > delimiters. Ignored
- if fetching by article number.
- flagReqd = true if BinHex or uuencode text
- must include special "begin" flag line.
-
- Exit: function result = true if article found in cache.
- *txt = handle to article text.
- *length = length of article text.
- *attachedFile = true if article contains an attached file.
-
- If the article is found in the cache, ownership of the relocatable block
- containing the full article text is transferred from the cache to the
- caller, and the block is made non-purgable.
- ----------------------------------------------------------------------------*/
-
- static Boolean GetArticleFromCache (char *groupName, long number, char *id,
- Boolean flagReqd, Handle *txt, long *length, Boolean *attachedFile)
- {
- short i;
- TCachedArticleInfo *p;
- Boolean match;
- Handle h1, h2;
-
- if (gArticleCache == nil) return false;
-
- /* Search the cache for the article. */
-
- for (i = 0, p = *gArticleCache; i < kMaxCachedArticles; i++, p++) {
- if (p->inUse && *p->txt != nil) {
- if (groupName != nil && p->groupName != nil) {
- match = MyStrEqual(groupName, *p->groupName) && number == p->number;
- } else if (id != nil && p->msgId != nil) {
- match = MyStrEqual(id, *p->msgId);
- } else {
- match = false;
- }
- match = match && flagReqd == p->flagReqd;
- if (match) {
- /* We found the article in the cache. Transfer ownership of the
- text to our caller, make the text nonpurgable, and free the cache slot. */
- *txt = p->txt;
- HNoPurge(*txt);
- *attachedFile = p->attachedFile;
- p->inUse = false;
- h1 = p->groupName;
- h2 = p->msgId;
- MyDisposeHandle(h1);
- MyDisposeHandle(h2);
- *length = MyGetHandleSize(*txt);
- return true;
- }
- }
- }
-
- return false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Rot13Text
-
- Rot13 text.
-
- Entry: text = handle to text.
- start = offset in text to start.
- end = offset in text to end.
- ----------------------------------------------------------------------------*/
-
- void Rot13Text (Handle text, long start, long end)
- {
- char *p, *pEnd;
-
- for (p = *text + start, pEnd = *text + end; p < pEnd; p++)
- if (isalpha(*p)) *p += (toupper(*p) > 'M') ? -13 : 13;
- }
-
-
-
- /*----------------------------------------------------------------------------
- GetTextRect
-
- Compute the "text" rectangle of an article window
-
- Entry: wind = pointer to article window.
-
- Exit: *textRect = text rectangle.
-
- The "text" rectangle is the area of the window where the text is
- displayed: the window portrect, minus the panel area, minus the scroll
- bars, minus the text margin.
- ----------------------------------------------------------------------------*/
-
- static void GetTextRect (WindowPtr wind, Rect *textRect)
- {
- TWindow **info;
-
- info = (TWindow**)GetWRefCon(wind);
- *textRect = wind->portRect;
- textRect->top += (**info).panelHeight;
- textRect->bottom -= 15;
- textRect->right -= 15;
- InsetRect(textRect, kTextMargin, kTextMargin);
- }
-
-
-
- /*----------------------------------------------------------------------------
- FixHeight
-
- Round down window height to an exact multiple of lines.
-
- Entry: wind = pointer to article window.
- *height = window height.
-
- Exit: *height = adjusted window height
- ----------------------------------------------------------------------------*/
-
- static void FixHeight (WindowPtr wind, short *height)
- {
- TWindow **info;
- short panelHeight, lineHeight, adjust;
-
- info = (TWindow**)GetWRefCon(wind);
- panelHeight = (**info).panelHeight;
- lineHeight = GetFontLineHeight(wind);
- adjust = panelHeight + 15 + 2*kTextMargin;
- *height = (*height - adjust) / lineHeight * lineHeight + adjust;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MinHeight
-
- Compute the minimum height of an article window.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static short MinHeight (WindowPtr wind)
- {
- TWindow **info;
- short lineHeight, height, extra;
-
- info = (TWindow**)GetWRefCon(wind);
- lineHeight = GetFontLineHeight(wind);
- extra = lineHeight + 15 + 2*kTextMargin;
- if (extra < 65) extra = 65 + lineHeight;
- height = (**info).panelHeight + extra;
- FixHeight(wind, &height);
- return height;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DrawSectionMessage
-
- Draw the "Section x of y" message in an article window.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void DrawSectionMessage (WindowPtr wind)
- {
- TWindow **info;
- short fontNum;
- CStr255 msg;
- CStr255 sectionMessageFormat;
- TextStyle savedStyle;
- short width, left;
-
- GetPortTextStyle(&savedStyle);
-
- info = (TWindow**)GetWRefCon(wind);
-
- MoveTo(16, wind->portRect.bottom - 15);
- LineTo(16, wind->portRect.bottom);
-
- GetCString(kStrSectionMessageFormat, sectionMessageFormat);
- GetFontNumber("\pMonaco", &fontNum);
- TextFont(fontNum);
- TextSize(9);
- sprintf(msg, sectionMessageFormat, (**info).curSection+1, (**info).numSections);
- c2pstr(msg);
- width = StringWidth((StringPtr)msg);
- left = 16 + ((kSectionMargin - 46 - width) >> 1);
- MoveTo(left, wind->portRect.bottom-4);
- DrawString((StringPtr)msg);
-
- DrawArrowPair((**info).sectionArrowPair);
-
- MoveTo(kSectionMargin - 30, wind->portRect.bottom - 15);
- LineTo(kSectionMargin - 30, wind->portRect.bottom);
- MoveTo(kSectionMargin - 15, wind->portRect.bottom - 15);
- LineTo(kSectionMargin - 15, wind->portRect.bottom);
- MoveTo(kSectionMargin, wind->portRect.bottom - 15);
- LineTo(kSectionMargin, wind->portRect.bottom);
-
- SetPortTextStyle(&savedStyle);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DrawPanelString
-
- Draw a string in the panel area of an article window.
-
- Entry: wind = pointer to article window.
- str = string to draw.
- v = vertical coordinate of string.
- width = max width of string.
- ----------------------------------------------------------------------------*/
-
- static void DrawPanelString (char *str, short v, short width)
- {
- if (width < 20) return;
- c2pstr(str);
- TruncString(width, (StringPtr)str, smTruncEnd);
- MoveTo(10, v);
- DrawString((StringPtr)str);
- p2cstr((StringPtr)str);
- }
-
-
-
- /*----------------------------------------------------------------------------
- ScrollSection
-
- Scroll an article window horizontally (by sections).
-
- Entry: wind = pointer to article window.
- dh = number of sections to scroll.
- ----------------------------------------------------------------------------*/
-
- static void ScrollSection (WindowPtr wind, short dh)
- {
- TWindow **info;
- TEHandle theTE;
- short curSection, newSection;
- Rect r, textRect;
- Handle text;
- long **breaks;
- long offset, length;
- char state;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- GetTextRect(wind, &textRect);
- curSection = (**info).curSection;
- (**info).curSection = newSection = curSection - dh;
- r = wind->portRect;
- r.top = r.bottom - 13;
- r.left += kTextMargin + 15;
- r.bottom -= 2;
- r.right = kSectionMargin - 32;
- EraseRect(&r);
- DrawSectionMessage(wind);
- EnableOrDisableArrowPair((**info).sectionArrowPair, -1,
- newSection > 0);
- EnableOrDisableArrowPair((**info).sectionArrowPair, +1,
- newSection < (**info).numSections - 1);
- text = (**info).fullText;
- breaks = (**info).sectionBreaks;
- offset = (*breaks)[newSection];
- length = (*breaks)[newSection+1] - offset;
- if (newSection == 0 && !(**info).showDetails) {
- offset = FindBody(text);
- if (offset > length) offset = length;
- length -= offset;
- }
- state = MyHGetState(text);
- MyHLock(text);
- TESetText(*text+offset, length, theTE);
- MyHSetState(text, state);
- TESetSelect(0, 0, theTE);
- SetControlValue((**info).vScroll,0);
- (**theTE).destRect = textRect;
- TEScrollAdjustScrollMax(theTE, (**info).vScroll);
- InvalRect(&textRect);
- HandleUpdate(wind);
- KillBalloon();
- }
-
-
-
- /*----------------------------------------------------------------------------
- ScrollActionSection
-
- Horizontal scroll bar action procedure (sections).
-
- Entry: hScroll = handle to horizontal scroll bar control
- part = part code.
- ----------------------------------------------------------------------------*/
-
- static pascal void ScrollActionSection (ControlHandle hScroll, short part)
- {
- WindowPtr wind;
- TWindow **info;
- short val, max, dh;
-
- wind = (**hScroll).contrlOwner;
- info = (TWindow**)GetWRefCon(wind);
- val = (**hScroll).contrlValue;
- max = (**hScroll).contrlMax;
- dh = 0;
- switch (part) {
- case inUpButton:
- case inPageUp:
- dh = val > 0 ? 1 : 0;
- break;
- case inDownButton:
- case inPageDown:
- dh = val < max ? -1 : 0;
- break;
- case kScrollToHome:
- dh = val;
- break;
- case kScrollToEnd:
- dh = val - max;
- break;
- }
- if (dh != 0) {
- SetControlValue(hScroll, val - dh);
- ScrollSection(wind, dh);
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- ScrollAction
-
- Vertical scroll bar action proc.
-
- Entry: vScroll = handle to vertical scroll bar control.
- part = part code.
- ----------------------------------------------------------------------------*/
-
- static pascal void ScrollAction (ControlHandle vScroll, short part)
- {
- WindowPtr wind;
- TWindow **info;
- TEHandle theTE;
-
- wind = (**vScroll).contrlOwner;
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- TEScrollScrollByPartCode(theTE, vScroll, part);
- }
-
-
-
- /*----------------------------------------------------------------------------
- AutoScroll
-
- Handle article window autoscrolling.
-
- Exit: function result = true
- ----------------------------------------------------------------------------*/
-
- static pascal Boolean AutoScroll (void)
- {
- WindowPtr wind;
- TWindow **info;
- ControlHandle vScroll;
- TEHandle theTE;
-
- wind = MyFrontWindow();
- if (wind == nil) return true;
- info = (TWindow**)GetWRefCon(wind);
- vScroll = (**info).vScroll;
- theTE = (**info).theTE;
- TEScrollAutoScroll(theTE, vScroll);
- return true;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ResizeContents
-
- Adjust an article window's contents after a window size change (grow
- or zoom).
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void ResizeContents (WindowPtr wind)
- {
- TWindow **info;
- short width, height, panelHeight;
- ControlHandle hScroll, vScroll;
- TEHandle theTE;
- Rect r;
- Point sectionArrowPairBotLeft, nextPrevArrowPairBotLeft;
-
- info = (TWindow**)GetWRefCon(wind);
- panelHeight = (**info).panelHeight;
- vScroll = (**info).vScroll;
- hScroll = (**info).hScroll;
- theTE = (**info).theTE;
- width = wind->portRect.right;
- height = wind->portRect.bottom;
-
- SetRect(&r, width-15, panelHeight-1, width+1, height-14);
- (**vScroll).contrlRect = r;
-
- if (hScroll != nil) {
- SetRect(&r, kSectionMargin, height-15, width-14, height+1);
- (**hScroll).contrlRect = r;
- }
-
- GetTextRect(wind, &r);
- (**theTE).viewRect = (**theTE).destRect = r;
- TECalText(theTE);
- SetControlValue(vScroll, 0);
- TEScrollAdjustScrollMax(theTE, vScroll);
- TEScrollScrollSelectionIntoView(theTE, vScroll);
-
- if ((**info).sectionArrowPair != nil) {
- SetPt(§ionArrowPairBotLeft, kSectionMargin - 26, height - 3);
- MoveArrowPair((**info).sectionArrowPair, sectionArrowPairBotLeft);
- }
-
- if ((**info).nextPrevArrowPair != nil) {
- SetPt(&nextPrevArrowPairBotLeft, wind->portRect.right - 17, 30);
- MoveArrowPair((**info).nextPrevArrowPair, nextPrevArrowPairBotLeft);
- }
-
- InvalRect(&wind->portRect);
-
- RecordNewLockedWindowPosition(wind, &gPrefs.articleWindLocn);
- }
-
-
-
- /*----------------------------------------------------------------------------
- FindNextSectionBreak
-
- Find the next section break in an article
-
- Entry: fullText = handle to full article text.
- len = length of full article text.
- offset = offset in full article text of previous break.
-
- Exit: function result = offset in full article text of next break
- ----------------------------------------------------------------------------*/
-
- static long FindNextSectionBreak (Handle fullText, long len, long offset)
- {
- char *p, *pEnd, *qStart, *qEnd, *q, *s, *qCR, *qCRCR;
-
- p = *fullText + offset;
- pEnd = *fullText + len;
- qEnd = p + 31999;
- if (qEnd > pEnd) qEnd = pEnd;
- for (q = p; q < qEnd; q++) {
- if (*q == FF) {
- return q - *fullText + 1;
- }
- }
- if (qEnd >= pEnd) return len;
- qStart = p + 31999;
- qCR = qCRCR = qEnd = p + 25010;
- for (q = qStart; q > qEnd; q--) {
- if (*q == CR) {
- qCR = q;
- if (*(q-1) == CR) {
- qCRCR = q;
- for (s = q-2; *s == '-' && s > qEnd; s--) /* do nothing */;
- if (*s == CR) break;
- }
- }
- }
- if (q <= qEnd) q = qCRCR;
- if (q <= qEnd) q = qCR;
- if (q <= qEnd) q = qStart;
- return q - *fullText;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MakeSections
-
- Split a large (>32K) block of text into sections.
-
- Entry: text = handle to large block of text.
-
- Exit: function result = error code.
- *sectionBreaks = section breaks.
- *numSections = number of sections.
- ----------------------------------------------------------------------------*/
-
- OSErr MakeSections (Handle text, long ***sectionBreaks, short *numSections)
- {
- long **breaks = nil;
- long len, offset, breaksAllocated;
- short n;
- OSErr err = noErr;
-
- len = MyGetHandleSize(text);
- err = MyNewHandle(10*sizeof(long), &breaks);
- if (err != noErr) goto exit;
- breaksAllocated = 10;
- offset = 0;
- n = 0;
- while (offset < len) {
- if (n+1 >= breaksAllocated) {
- breaksAllocated += 10;
- err = MySetHandleSize(breaks, breaksAllocated*sizeof(long));
- if (err != noErr) goto exit;
- }
- (*breaks)[n++] = offset;
- offset = FindNextSectionBreak(text, len, offset);
- }
- (*breaks)[n] = len;
- MySetHandleSize(breaks, (n+1)*sizeof(long));
- *numSections = n;
- *sectionBreaks = breaks;
-
- return noErr;
-
- exit:
-
- MyDisposeHandle(breaks);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CalcSectionBreaks
-
- Calculate section breaks for an article larger than 32K and create the
- horizontal scroll bar.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr CalcSectionBreaks (WindowPtr wind)
- {
- TWindow **info;
- Handle fullText;
- long **breaks = nil;
- short numSections;
- Rect r;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- fullText = (**info).fullText;
- err = MakeSections(fullText, &breaks, &numSections);
- if (err != noErr) goto exit;
- (**info).numSections = numSections;
- (**info).curSection = 0;
- (**info).sectionBreaks = breaks;
-
- if (numSections > 1) {
- SetRect(&r, kSectionMargin, wind->portRect.bottom - 15,
- wind->portRect.right - 14, wind->portRect.bottom + 1);
- (**info).hScroll = NewControl(wind, &r, "\p", true, 0, 0,
- numSections-1, scrollBarProc, 0);
- }
-
- return noErr;
-
- exit:
-
- MyDisposeHandle(breaks);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ComputePanelInfo
-
- Compute information about the panel area of a new article window.
-
- Entry: wind = pointer to article window.
- txt = handle to full article text.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr ComputePanelInfo (WindowPtr wind, Handle txt)
- {
- TWindow **info;
- short lineHeight;
- short panelHeight;
- short numPanelLines;
- Handle from = nil;
- Handle newsgroups = nil;
- Handle followupto = nil;
- Handle replyto = nil;
- long fromLen, newsgroupsLen, followuptoLen, replytoLen;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- lineHeight = GetFontLineHeight(wind);
- if (lineHeight < 11) lineHeight = 11;
-
- err = FindHeaderHandle(txt, "From", &from);
- if (err != noErr) goto exit;
- err = FindHeaderHandle(txt, "Newsgroups", &newsgroups);
- if (err != noErr) goto exit;
- err = FindHeaderHandle(txt, "Followup-To", &followupto);
- if (err != noErr) goto exit;
- err = FindHeaderHandle(txt, "Reply-To", &replyto);
- if (err != noErr) goto exit;
-
- (**info).showReplyTo = (**info).showFollowupTo = false;
-
- if (from != nil && replyto != nil) {
- fromLen = MyGetHandleSize(from);
- replytoLen = MyGetHandleSize(replyto);
- (**info).showReplyTo = fromLen != replytoLen ||
- !MyStrNEqual(*from, *replyto, fromLen);
- }
-
- if (newsgroups != nil && followupto != nil) {
- newsgroupsLen = MyGetHandleSize(newsgroups);
- followuptoLen = MyGetHandleSize(followupto);
- (**info).showFollowupTo = newsgroupsLen != followuptoLen ||
- !MyStrNEqual(*newsgroups, *followupto, newsgroupsLen);
- }
-
- numPanelLines = 4;
- if ((**info).showReplyTo) numPanelLines++;
- if ((**info).showFollowupTo) numPanelLines++;
-
- panelHeight = numPanelLines*lineHeight + 9;
- (**info).panelHeight = panelHeight;
-
- exit:
-
- MyDisposeHandle(from);
- MyDisposeHandle(newsgroups);
- MyDisposeHandle(followupto);
- MyDisposeHandle(replyto);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckFirstLastArticle
-
- Check to see if an article is the first or last one in its parent subject
- window.
-
- Entry: wind = pointer to article window.
-
- Exit: *first = true if article is first one.
- *last = true if article is last one.
- ----------------------------------------------------------------------------*/
-
- static void CheckFirstLastArticle (WindowPtr wind, Boolean *first, Boolean *last)
- {
- TWindow **info, **parentInfo;
- WindowPtr parentWindow;
- TSubject **subjectArray;
- short index, lastCell;
- TSubject theSubject;
- ListHandle theList;
- Cell theCell;
-
- info = (TWindow**)GetWRefCon(wind);
- parentWindow = (**info).parentWindow;
- if (parentWindow == nil) return;
- index = (**info).parentSubject;
- parentInfo = (TWindow**)GetWRefCon(parentWindow);
- subjectArray = (**parentInfo).subjectArray;
- theSubject = (*subjectArray)[index];
- theList = (**parentInfo).theList;
- lastCell = (**theList).dataBounds.bottom - 1;
- if (theSubject.collapsed) {
- FindParentCell(parentWindow, theSubject.threadHeadIndex, &theCell);
- *first = theCell.v == 0 && theSubject.threadOrdinal == 1;
- *last = theCell.v == lastCell && theSubject.threadOrdinal == theSubject.threadLength;
- } else {
- FindParentCell(parentWindow, index, &theCell);
- *first = theCell.v == 0;
- *last = theCell.v == lastCell;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- EnableOrDisableNextPrevArrows
-
- Enable/disable the next/prev article arrow controls in an article window.
-
- Entry: wind = pointer to article window.
-
- The next article (down) arrow is enabled iff this article is not the
- last article in the parent subject window.
- The prev article (up) arrow is enabled iff this article is not the
- first article in the parent subject window.
- ----------------------------------------------------------------------------*/
-
- static void EnableOrDisableNextPrevArrows (WindowPtr wind)
- {
- TWindow **info;
- Boolean first, last;
- ArrowPairRef nextPrevArrowPair;
-
- info = (TWindow**)GetWRefCon(wind);
- nextPrevArrowPair = (**info).nextPrevArrowPair;
- CheckFirstLastArticle(wind, &first, &last);
- EnableOrDisableArrowPair(nextPrevArrowPair, -1, !first);
- EnableOrDisableArrowPair(nextPrevArrowPair, +1, !last);
- }
-
-
- /*----------------------------------------------------------------------------
- MakeNewWindow
-
- Create a new article window.
-
- Entry: groupName = name of group, or nil if fetching by message id.
- number = article number. Ignored if fetching by message id.
- id = message id string, including < and > delimiters, or nil
- if article was fetched by article number.
- parent = pointer to parent subject window, or nil if opening by id.
- checkTitle = true if window title should contain checkmark.
- reuse = pointer to article window to be reused, or nil to
- open new article window.
- flagReqd = true if BinHex or uuencode text
- must include special "begin" flag line.
- txt = handle to article text.
- length = length of article text.
- attachedFile = true if article contains attached file.
-
- Exit: function result = error code.
- *theWindow = pointer to new article window.
- ----------------------------------------------------------------------------*/
-
- static OSErr MakeNewWindow (char *groupName, long number,
- char *id, WindowPtr parent, Boolean checkTitle, WindowPtr reuse,
- Boolean flagReqd, Handle txt, long length, Boolean attachedFile,
- WindowPtr *theWindow)
- {
- short panelHeight, width, height;
- WindowPtr wind = nil;
- TWindow **info;
- Rect r;
- TEHandle theTE;
- ControlHandle vScroll;
- Handle fullText;
- long offset;
- OSErr err = noErr;
- Handle msgId, groupNameHandle;
- CStr255 title;
- short len;
- char state;
- GrafPtr port;
- short zoomDir;
- Rect arrowRect, backwardHotRect, forwardHotRect;
- ArrowPairRef sectionArrowPair, nextPrevArrowPair;
-
- MyICReadSharedPrefs(kICScreenFont);
-
- GetPort(&port);
-
- FindHeaderCString(txt, "Subject", title, sizeof(title));
- c2pstr(title);
- if (checkTitle) {
- len = (unsigned char)title[0];
- if (len == 255) len = 254;
- BlockMoveData(title + 1, title + 2, len);
- title[1] = checkMark;
- title[0] = len + 1;
- }
-
- if (reuse == nil) {
-
- err = CreateNewWindow(kArticle, (StringPtr)title,
- gPrefs.textFont, gPrefs.textSize, &wind);
- if (err != noErr) goto exit;
- SetPort(wind);
- info = (TWindow**)GetWRefCon(wind);
- err = ComputePanelInfo(wind, txt);
- if (err != noErr) goto exit;
- panelHeight = (**info).panelHeight;
- width = kMinWindowWidth;
- height = MinHeight(wind);
- RestoreLockedWindowPosition(wind, width, height, gPrefs.articleWindPosLocked,
- &gPrefs.articleWindLocn);
- width = wind->portRect.right;
- height = wind->portRect.bottom;
- SetRect(&r, width-15, panelHeight-1, width+1, height-14);
- vScroll = NewControl(wind, &r, "\p", false, 0, 0, 0, scrollBarProc, 1);
- (**info).vScroll = vScroll;
- zoomDir = inZoomOut;
-
- } else {
-
- SaveArticleInCache(reuse);
- wind = reuse;
- SetPort(wind);
- SetWTitle(wind, (StringPtr)title);
- InvalRect(&wind->portRect);
- info = (TWindow**)GetWRefCon(wind);
- err = ComputePanelInfo(wind, txt);
- if (err != noErr) goto exit;
- panelHeight = (**info).panelHeight;
- width = wind->portRect.right;
- height = wind->portRect.bottom;
- SetRect(&r, width-15, panelHeight-1, width+1, height-14);
- vScroll = (**info).vScroll;
- (**vScroll).contrlRect = r;
- SetControlValue(vScroll, 0);
- TEDispose((**info).theTE);
- (**info).theTE = nil;
- MyDisposeHandle((**info).sectionBreaks);
- (**info).sectionBreaks = nil;
- if ((**info).hScroll != nil) DisposeControl((**info).hScroll);
- (**info).hScroll = nil;
- DisposeArrowPair((**info).sectionArrowPair);
- (**info).sectionArrowPair = nil;
- DisposeArrowPair((**info).nextPrevArrowPair);
- (**info).nextPrevArrowPair = nil;
- RemoveChild(parent, wind);
- (**info).maxBodyLineWidth = 0;
- (**info).numBodyLines = 0;
- zoomDir = zoomOutOnlyIfBigger;
-
- }
-
- GetTextRect(wind, &r);
- theTE = TENew(&r, &r);
- (**theTE).clickLoop = gAutoScrollUPP;
- if (gHaveTEOutlineHilite) TEFeatureFlag(teFOutlineHilite, TEBitSet, theTE);
-
- (**info).theTE = theTE;
- (**info).parentWindow = parent;
- (**info).fullText = fullText = txt;
- txt = nil;
- (**info).showDetails = gPrefs.showArtHeaders;
- (**info).attachedFile = attachedFile;
-
- if (groupName == nil) {
- (**info).groupName = nil;
- } else {
- err = MyPtrToHand(groupName, &groupNameHandle, strlen(groupName) + 1);
- if (err != noErr) goto exit;
- (**info).groupName = groupNameHandle;
- (**info).number = number;
- }
- (**info).flagReqd = flagReqd;
-
- if (parent == nil) {
- err = MyPtrToHand(id, &msgId, strlen(id)+1);
- if (err != noErr) goto exit;
- (**info).msgId = msgId;
- } else {
- err = AddChild(parent, wind);
- if (err != noErr) goto exit;
- }
-
- err = CalcSectionBreaks(wind);
- if (err != noErr) goto exit;
- length = (*(**info).sectionBreaks)[1];
-
- offset = gPrefs.showArtHeaders ? 0 : FindBody(fullText);
- if (offset > length) offset = length;
- state = MyHGetState(fullText);
- MyHLock(fullText);
- err = MyTESetText(*fullText+offset, length-offset, theTE);
- MyHSetState(fullText, state);
- if (err != noErr) goto exit;
-
- TESetSelect(0, 0, theTE);
-
- if ((**info).numSections > 1) {
- SetRect(&arrowRect, kSectionMargin - 26, wind->portRect.bottom - 13,
- kSectionMargin - 4, wind->portRect.bottom - 3);
- SetRect(&backwardHotRect, kSectionMargin - 30, wind->portRect.bottom - 15,
- kSectionMargin - 15, wind->portRect.bottom);
- forwardHotRect = backwardHotRect;
- OffsetRect(&forwardHotRect, 15, 0);
- err = CreateArrowPair(false, &arrowRect, &backwardHotRect,
- &forwardHotRect, §ionArrowPair);
- if (err != noErr) goto exit;
- EnableOrDisableArrowPair(sectionArrowPair, -1, false);
- (**info).sectionArrowPair = sectionArrowPair;
- }
-
- if (parent != nil) {
- SetRect(&arrowRect, wind->portRect.right - 17, 8, wind->portRect.right - 5, 30);
- backwardHotRect = forwardHotRect = arrowRect;
- backwardHotRect.bottom = forwardHotRect.top = 21;
- backwardHotRect.top++;
- forwardHotRect.bottom++;
- err = CreateArrowPair(true, &arrowRect, &backwardHotRect,
- &forwardHotRect, &nextPrevArrowPair);
- if (err != noErr) goto exit;
- (**info).nextPrevArrowPair = nextPrevArrowPair;
- }
-
- if (!(**info).windPosLocked) {
- err = DoZoom(wind, zoomDir);
- if (err != noErr) goto exit;
- }
-
- TEScrollAdjustScrollMax(theTE, (**info).vScroll);
-
- if (reuse != nil) {
- if ((**info).hScroll != nil) ShowControl((**info).hScroll);
- TEActivate(theTE);
- }
-
- *theWindow = wind;
- SetPort(port);
- return noErr;
-
- exit:
-
- MyDisposeHandle(txt);
- DoClose(wind);
- SetPort(port);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- GetArticleAndMakeNewWindow
-
- Get an article from the news server and create a new article window.
-
- Entry: host = address of news server, or nil to use default server.
- port = port number on news server if host not nil.
- groupName = name of group, or nil if fetching by message id.
- number = article number. Ignored if fetching by message id.
- id = message id string, including < and > delimiters. Ignored
- if fetching by article number.
- parent = pointer to parent subject window, or nil if opening by id.
- checkTitle = true if window title should contain checkmark.
- reuse = pointer to article window to be reused, or nil to
- open new article window.
- flagReqd = true if BinHex or uuencode text
- must include special "begin" flag line.
-
- Exit: function result = error code.
- *theWindow = pointer to new article window, or nil if article
- does not exist on server.
- ----------------------------------------------------------------------------*/
-
- static OSErr GetArticleAndMakeNewWindow (char *host, short port,
- char *groupName, long number, char *id,
- WindowPtr parent, Boolean checkTitle, WindowPtr reuse,
- Boolean flagReqd, WindowPtr *theWindow)
- {
- Handle txt = nil;
- long length;
- OSErr err = noErr;
- Boolean attachedFile;
-
- if (host != nil || !GetArticleFromCache(groupName, number, id,
- flagReqd, &txt, &length, &attachedFile))
- {
- err = GetArticle(host, port, groupName, number, id, "ARTICLE", true,
- flagReqd, &txt, &length, &attachedFile);
- if (err != noErr) return err;
- if (txt == nil) {
- *theWindow = nil;
- return noErr;
- }
- }
-
- return MakeNewWindow(groupName, number, id, parent, checkTitle, reuse,
- flagReqd, txt, length, attachedFile, theWindow);
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckAlreadyOpen
-
- Check to see if a referenced article window is already open. If it is,
- bring it to the front.
-
- Entry: msgId = C-format message id of article.
-
- Exit: function result = true if window already open.
- ----------------------------------------------------------------------------*/
-
- static Boolean CheckAlreadyOpen (char *msgId)
- {
- WindowPtr wind;
- TWindow **info;
- TWindowKind kind;
-
- wind = FrontWindow();
- while (wind != nil) {
- kind = GetMyWindowKind(wind);
- if (kind == kArticle) {
- info = (TWindow**)GetWRefCon(wind);
- if ((**info).msgId != nil) {
- if (strcmp(msgId, *(**info).msgId) == 0) {
- MySelectWindow(wind);
- return true;
- }
- }
- }
- wind = (WindowPtr)(((WindowPeek)wind)->nextWindow);
- }
- return false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- OpenSubjectCell
-
- Open an article window corresponding to a cell in a subject window.
-
- Entry: wind = pointer to subject window.
- theCell = the cell in the subject window to open.
- threadOrdinal = ordinal of article within thread to open if
- theCell is a collapsed thread, else 1.
- reuse = pointer to article window to be reused, or nil to
- open new article window.
-
- Exit: function result = error code.
- *child = pointer to opened article window, or nil if
- article does not exist on server.
- ----------------------------------------------------------------------------*/
-
- OSErr OpenSubjectCell (WindowPtr wind, Cell theCell, short threadOrdinal,
- WindowPtr reuse, WindowPtr *child)
- {
- WindowPtr newWind = nil;
- TWindow **info, **newInfo;
- ListHandle theList;
- TSubject **subjectArray;
- CStr255 groupName;
- short index, cellDataLen;
- long number;
- OSErr err = noErr;
- Boolean flagReqd;
-
- info = (TWindow**) GetWRefCon(wind);
- theList = (**info).theList;
- subjectArray = (**info).subjectArray;
-
- cellDataLen = 2;
- LGetCell(&index, &cellDataLen ,theCell, theList);
- while (threadOrdinal-- > 1)
- index = (*subjectArray)[index].nextInThread;
-
- if ((newWind = FindChildByIndex(wind, index)) != nil) {
- MySelectWindow(newWind);
- *child = newWind;
- return noErr;
- }
-
- number = (*subjectArray)[index].number;
- flagReqd = EncodedTextBeginLineIsRequired(subjectArray, index);
-
- strcpy(groupName, *gGroupNames + (**info).groupNameOffset);
-
- err = GetArticleAndMakeNewWindow(nil, 0, groupName, number, nil, wind, true, reuse,
- flagReqd, &newWind);
- if (err != noErr) goto exit;
-
- if (newWind != nil) {
- newInfo = (TWindow**)GetWRefCon(newWind);
- (**newInfo).parentSubject = index;
- err = MarkArticle(newWind, true);
- if (err != noErr) goto exit;
- EnableOrDisableNextPrevArrows(newWind);
- if (reuse == nil) MyShowWindow(newWind);
- }
-
- *child = newWind;
- return noErr;
-
- exit:
-
- DoClose(newWind);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- OpenReferencedArticle
-
- Open a referenced article.
-
- Entry: obj = message id or news URL of referenced article.
-
- Exit: function result = error code (fnfErr if article not found).
- ----------------------------------------------------------------------------*/
-
- OSErr OpenReferencedArticle (CStr255 obj)
- {
- CStr255 msgId;
- WindowPtr newWind = nil;
- OSErr err = noErr;
-
- if (MyStrNEqual(obj, "news:", 5)) {
- sprintf(msgId, "<%s>", obj+5);
- } else if (MyStrNEqual(obj, "<news:", 6)) {
- sprintf(msgId, "<%s", obj+6);
- } else {
- strcpy(msgId, obj);
- }
-
- if (CheckAlreadyOpen(msgId)) return noErr;
-
- err = GetArticleAndMakeNewWindow(nil, 0, nil, 0, msgId, nil, false, nil, true, &newWind);
- if (err != noErr) return err;
- if (newWind == nil) {
- return fnfErr;
- } else {
- MyShowWindow(newWind);
- return noErr;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- OpenArticleOnAnyServer
-
- Open an article on any server, perhaps a different server from the
- default one (for opening nntp URLs).
-
- Entry: host = address of news server.
- port = port number.
- newsgroup = newsgroup name.
- artNumber = article number.
-
- Exit: function result = error code (fnfErr if article not found).
- ----------------------------------------------------------------------------*/
-
- OSErr OpenArticleOnAnyServer (char *host, short port,
- char *newsgroup, long artNumber)
- {
- WindowPtr newWind;
- OSErr err = noErr;
-
- err = GetArticleAndMakeNewWindow(host, port, newsgroup, artNumber,
- nil, nil, false, nil, true, &newWind);
- if (err != noErr) return err;
- if (newWind == nil) {
- return fnfErr;
- } else {
- MyShowWindow(newWind);
- return noErr;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- FormFileName
-
- Form the default file name for saving an article.
-
- Entry: wind = pointer to article window.
-
- Exit: fileName = default file name.
- ----------------------------------------------------------------------------*/
-
- static void FormFileName (WindowPtr wind, Str31 fileName)
- {
- Str255 title;
-
- GetWTitle(wind, title);
- if (title[0] > 0 && title[1] == checkMark) {
- title[0]--;
- BlockMoveData(title+2, title+1, title[0]);
- }
- MakeLegalFileName(title, fileName);
- }
-
-
-
- /*----------------------------------------------------------------------------
- PresentStandardArticleSaveFileDialog
-
- Present the standard save file dialog.
-
- Entry: fileName = default file name.
- *saveEncodedText = default value for save encoded text option.
- *saveThreadsToSeparateFiles = default value for save threads
- to separate files option.
-
- Exit: function result = error code.
- *fSpec = file spec.
- *scriptTag = script code.
- *saveEncodedText = true to save encoded text.
- *saveThreadsToSeparateFiles = true to save threads to separate
- files.
- ----------------------------------------------------------------------------*/
-
- OSErr PresentStandardArticleSaveFileDialog (Str31 fileName, FSSpec *fSpec,
- ScriptCode *scriptTag, Boolean *saveEncodedText,
- Boolean *saveThreadsToSeparateFiles)
- {
- StandardFileReply reply;
- Str255 prompt;
-
- GetPString(kStrSaveArticlePrompt, prompt);
- MyStandardPutArticle(prompt, fileName, &reply,
- saveEncodedText, saveThreadsToSeparateFiles,
- gPrefs.savedArtDefaultFolder ? gPrefs.savedArtDefaultFolderAlias : nil);
- if (!reply.sfGood) return userCanceledErr;
- *fSpec = reply.sfFile;
- *scriptTag = reply.sfScript;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- PresentStandardArticleGetFileDialog
-
- Present the standard get file dialog.
-
- Entry: *saveEncodedText = default value of save encoded text option.
-
- Exit: function result = error code.
- *fSpec = file spec.
- *saveEncodedText = true to save encoded text.
- ----------------------------------------------------------------------------*/
-
- OSErr PresentStandardArticleGetFileDialog (FSSpec *fSpec, Boolean *saveEncodedText)
- {
- StandardFileReply reply;
-
- MyStandardAppendArticle(nil, 1, "TEXT", &reply, saveEncodedText,
- gPrefs.savedArtDefaultFolder ? gPrefs.savedArtDefaultFolderAlias : nil);
- if (!reply.sfGood) return userCanceledErr;
- *fSpec = reply.sfFile;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- SaveTextToArticleFile
-
- Save text to a file.
-
- Entry: text = handle to text to be saved.
- start = offset in text of first char to save.
- end = offset in text following last char char to save.
- fSpec = pointer to file spec.
- scriptTag = script code.
- append = true to append text to end of file.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr SaveTextToArticleFile (Handle text, long start, long end,
- FSSpec *fSpec, ScriptCode scriptTag, Boolean append)
- {
- OSErr err = noErr;
- long length;
- short refNum = 0;
- char state;
- char *separator, *p;
- Boolean needCR, empty;
-
- state = MyHGetState(text);
-
- err = OpenDataForkWriteCreateIfMissing(fSpec, gPrefs.savedArtCreator, 'TEXT',
- scriptTag, append, &refNum, &empty);
- if (err != noErr) goto exit;
-
- if (append && !empty) {
- separator =
- "\r----------------------------------------------------------------------\r\r";
- length = strlen(separator);
- err = MyFSWriteNoCache(refNum, &length, separator, GiveTime);
- if (err != noErr) goto exit;
- }
-
- length = end - start;
- MyHLock(text);
-
- for (p = *text + end - 1; p >= *text + start && *p == CR; p--) /* do nothing */;
- p++;
- if (p < *text + end) {
- needCR = false;
- length = p + 1 - *text - start;
- } else {
- needCR = true;
- }
-
- err = MyFSWriteNoCache(refNum, &length, *text + start, GiveTime);
- if (err != noErr) goto exit;
- if (needCR) {
- length = 1;
- err = MyFSWriteNoCache(refNum, &length, CRSTR, GiveTime);
- if (err != noErr) goto exit;
- }
- MyHSetState(text, state);
- MyFSClose(refNum, GiveTime);
- return noErr;
-
- exit:
-
- MyHSetState(text, state);
- if (refNum != 0) MyFSClose(refNum, GiveTime);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- GetAndSaveFullTextToArticleFile
-
- Get the full text of an article with attached binaries and save it
- to a file.
-
- Entry: wind = pointer to article window.
- fSpec = pointer to file spec.
- scriptTag = script code.
- append = true to append text to end of file.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr GetAndSaveFullTextToArticleFile (WindowPtr wind,
- FSSpec *fSpec, ScriptCode scriptTag, Boolean append)
- {
- OSErr err = noErr;
- long length;
- short refNum = 0;
- char *separator;
- Boolean empty;
- TWindow **info, **parentInfo;
- WindowPtr parent;
- TSubject **subjectArray;
- short index;
- CStr255 groupName;
- long number;
- TAttachedFileKind partKind;
- Handle msgId;
- char state;
-
- err = DisplayStatusMessageNumber(kStrGettingAndSavingArticle);
- if (err != noErr) return err;
-
- err = OpenDataForkWriteCreateIfMissing(fSpec, gPrefs.savedArtCreator, 'TEXT',
- scriptTag, append, &refNum, &empty);
- if (err != noErr) goto exit;
-
- if (append && !empty) {
- separator =
- "\r----------------------------------------------------------------------\r\r";
- length = strlen(separator);
- err = MyFSWriteNoCache(refNum, &length, separator, GiveTime);
- if (err != noErr) goto exit;
- }
-
- info = (TWindow**)GetWRefCon(wind);
- parent = (**info).parentWindow;
-
- if (parent == nil) {
-
- msgId = (**info).msgId;
- state = MyHGetState(msgId);
- MyHLockHi(msgId);
- err = CopyArticleToFile(nil, 0, *msgId, "ARTICLE", refNum,
- false, false, &partKind);
- MyHSetState(msgId, state);
- if (err != noErr) goto exit;
-
- } else {
-
- parentInfo = (TWindow**)GetWRefCon(parent);
- subjectArray = (**parentInfo).subjectArray;
- index = (**info).parentSubject;
- strcpy(groupName, *gGroupNames + (**parentInfo).groupNameOffset);
- number = (*subjectArray)[index].number;
- err = CopyArticleToFile(groupName, number, nil, "ARTICLE", refNum,
- false, false, &partKind);
- if (err != noErr) goto exit;
-
- }
-
- MyFSClose(refNum, GiveTime);
- return noErr;
-
- exit:
-
- if (refNum != 0) MyFSClose(refNum, GiveTime);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckArticleFileExists
-
- Check to see if an article file already exists in the default article
- file save directory. If it does, present an alert asking the user to
- append, replace, cancel, or pick a new name. If the "Append if file
- alread exists" preference is turned on, automatically append.
-
- Entry: fileName = file name.
- *saveEncodedText = default value for save encoded text
- option.
- *saveThreadsToSeparateFiles = default value for save threads
- to separate files option.
-
- Exit: function result = error code.
- *fSpec = file spec.
- *scriptTag = script code.
- *append = true to append.
- *saveEncodedText = true to save encoded text.
- *saveThreadsToSeparateFiles = true to save threads to
- separate files.
- ----------------------------------------------------------------------------*/
-
- OSErr CheckArticleFileExists (Str31 fileName, FSSpec *fSpec,
- ScriptCode *scriptTag, Boolean *append,
- Boolean *saveEncodedText, Boolean *saveThreadsToSeparateFiles)
- {
- OSErr err = noErr;
- DialogPtr dlg = nil;
- Boolean valid;
- short item;
-
- *append = false;
- ValidateSavedFolderAlias(gPrefs.savedArtDefaultFolderAlias,
- &fSpec->vRefNum, &fSpec->parID, &valid);
- if (!valid) {
- ErrorMessageNumber(kStrDefaultArtFoldNotFound);
- err = PresentStandardArticleSaveFileDialog(fileName, fSpec, scriptTag,
- saveEncodedText, saveThreadsToSeparateFiles);
- if (err != noErr) return err;
- return noErr;
- }
- *scriptTag = smSystemScript;
- CopyPascalString(fSpec->name, fileName);
- *append = gPrefs.appendIfFileAlreadyExists;
- err = FileOrFolderExists(fSpec);
- if (err == fnfErr) return noErr;
- if (err != noErr) return err;
- if (gPrefs.appendIfFileAlreadyExists) return noErr;
- *append = false;
- err = MyGetNewDialog(kArticleFileExistsAlert, 1, 2, &dlg);
- if (err != noErr) return err;
- ParamText(fileName, "\p", "\p", "\p");
- SetItemKeyEquivalent(dlg, 3, 'R');
- SetItemKeyEquivalent(dlg, 4, 'A');
- SetItemKeyEquivalent(dlg, 5, 'D');
- SysBeep(0);
- MyModalDialog(dlg, gDialogFilterUPP, &item);
- if (item == 5) DlgFlashButton(dlg, 4);
- err = DoClose(dlg);
- if (err != noErr) return err;
- switch (item) {
- case 1: /* Pick a New Name */
- err = PresentStandardArticleSaveFileDialog(fileName, fSpec,
- scriptTag, saveEncodedText, saveThreadsToSeparateFiles);
- if (err != noErr) return err;
- return noErr;
- case 2: /* Cancel */
- return userCanceledErr;
- case 3: /* Replace */
- return noErr;
- case 4: /* Append */
- case 5: /* Append (off screen, Cmd-D equiv.) */
- *append = true;
- return noErr;
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- SaveArticleWindToFile
-
- Save article window text to a file.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
- fSpec = pointer to file spec.
- scriptTag = script code.
- append = true to append text to end of file.
- saveEncodedText = true to save encoded text.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr SaveArticleWindToFile (WindowPtr wind, short modifiers,
- FSSpec *fSpec, ScriptCode scriptTag, Boolean append,
- Boolean saveEncodedText)
- {
- TWindow **info;
- long start, end;
- Handle text;
- TEHandle theTE;
- Boolean shift;
-
- MyICReadSharedPrefs(kICeditorHelper);
-
- info = (TWindow**)GetWRefCon(wind);
- shift = (modifiers & shiftKey) != 0;
-
- if (!shift && saveEncodedText && (**info).attachedFile) {
-
- return GetAndSaveFullTextToArticleFile(wind, fSpec, scriptTag, append);
-
- } else {
-
- if (shift) {
- theTE = (**info).theTE;
- text = (**theTE).hText;
- start = (**theTE).selStart;
- end = (**theTE).selEnd;
- } else {
- text = (**info).fullText;
- start = 0;
- end = MyGetHandleSize(text);
- }
- return SaveTextToArticleFile(text, start, end, fSpec, scriptTag, append);
-
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckForMissingParts
-
- Check for missing parts before trying to extract binaries for an article
- window.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr CheckForMissingParts (WindowPtr wind)
- {
- TWindow **info, **parentInfo;
- WindowPtr parent;
- TSubject **subjectArray;
- short index;
-
- info = (TWindow**)GetWRefCon(wind);
- parent = (**info).parentWindow;
- parentInfo = (TWindow**)GetWRefCon(parent);
- subjectArray = (**parentInfo).subjectArray;
- index = (**info).parentSubject;
- if ((*subjectArray)[index].incomplete) {
- NoteMessageNumber(kStrDecodePartsMissing);
- return userCanceledErr;
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- PresentStandardDownloadSaveFileDialog
-
- Present the standard file dialog for the temp file for extracting
- binaries.
-
- Entry: fileName = default file name.
-
- Exit: function result = error code.
- *fSpec = file spec.
- *scriptTag = script code.
- ----------------------------------------------------------------------------*/
-
- OSErr PresentStandardDownloadSaveFileDialog (Str31 fileName, FSSpec *fSpec,
- ScriptCode *scriptTag)
- {
- StandardFileReply reply;
- Str255 prompt;
-
- MyICReadSharedPrefs(kICDownloadFolder);
-
- GetPString(kStrDownloadTempFilePrompt, prompt);
- MyStandardPutFile(prompt, fileName, &reply,
- gPrefs.savedBinDefaultFolder ? gPrefs.savedBinDefaultFolderAlias : nil);
- if (!reply.sfGood) return userCanceledErr;
- *fSpec = reply.sfFile;
- *scriptTag = reply.sfScript;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckDownloadFileExists
-
- Check to see if a temp file already exists in the download directory.
- If it does, make the temp file name unique.
-
- Entry: fileName = default file name.
-
- Exit: function result = error code.
- *fSpec = file spec.
- *scriptTag = script code.
- ----------------------------------------------------------------------------*/
-
- OSErr CheckDownloadFileExists (Str31 fileName, FSSpec *fSpec,
- ScriptCode *scriptTag)
- {
- OSErr err = noErr;
- Boolean valid;
-
- MyICReadSharedPrefs(kICDownloadFolder);
-
- ValidateSavedFolderAlias(gPrefs.savedBinDefaultFolderAlias,
- &fSpec->vRefNum, &fSpec->parID, &valid);
- if (!valid) {
- ErrorMessageNumber(kStrDownloadFoldNotFound);
- err = PresentStandardDownloadSaveFileDialog(fileName, fSpec, scriptTag);
- if (err != noErr) return err;
- return noErr;
- }
- *scriptTag = smSystemScript;
- CopyPascalString(fSpec->name, fileName);
- return MakeFileNameUnique(fSpec, nil);
- }
-
-
-
- /*----------------------------------------------------------------------------
- SaveBinariesToFile
-
- Save binaries to a file for an article.
-
- Entry: wind = pointer to subject window.
- index = index in subject array of article.
- fSpec = pointer to file spec.
- scriptTag = script code.
- artNum = article number being saved (1,2,3,...numArts).
- numArts = total number of articles being saved.
-
- Exit: function result = error code.
- *fileKind = kind of attached file.
- ----------------------------------------------------------------------------*/
-
- static OSErr SaveBinariesToFile (WindowPtr wind, short index, FSSpec *fSpec,
- ScriptCode scriptTag, short artNum, short numArts,
- TAttachedFileKind *fileKind)
- {
- TWindow **info;
- TSubject **subjectArray;
- short numPartsToSave;
- CStr255 statusMsg, statusMsgFormat;
- Boolean append = false;
- short partNum, nextIndex, threadHeadIndex, n;
- Handle text = nil;
- long number;
- CStr255 groupName;
- Boolean empty, hasParts;
- OSErr err = noErr;
- short refNum;
- TAttachedFileKind partKind;
- Cell theCell;
-
- MyICReadSharedPrefs(kICeditorHelper);
-
- info = (TWindow**)GetWRefCon(wind);
- subjectArray = (**info).subjectArray;
- strcpy(groupName, *gGroupNames + (**info).groupNameOffset);
-
- *fileKind = kNoAttachedFile;
-
- threadHeadIndex = (*subjectArray)[index].threadHeadIndex;
-
- if ((*subjectArray)[index].numParts == 0x7fff) {
- hasParts = false;
- numPartsToSave = 1;
- partNum = 1;
- } else {
- hasParts = true;
- numPartsToSave = (*subjectArray)[index].numParts;
- index = threadHeadIndex;
- }
-
- if (numArts > 1) {
- GetCString(kStrGettingAndSavingArtAofBPartNofM, statusMsgFormat);
- } else if (hasParts) {
- GetCString(kStrGettingAndSavingPartNofM, statusMsgFormat);
- } else {
- GetCString(kStrGettingAndSavingFile, statusMsg);
- }
-
- err = OpenDataForkWriteCreateIfMissing(fSpec, gPrefs.savedArtCreator, 'TEXT',
- scriptTag, false, &refNum, &empty);
- if (err != noErr) return err;
-
- while (true) {
- if (hasParts) {
- while (index != -1 && (*subjectArray)[index].partNum == 0x7fff)
- index = (*subjectArray)[index].nextInThread;
- if (index == -1) break;
- partNum = (*subjectArray)[index].partNum;
- while (true) {
- nextIndex = (*subjectArray)[index].nextInThread;
- while (nextIndex != -1 && (*subjectArray)[nextIndex].partNum == 0x7fff)
- nextIndex = (*subjectArray)[nextIndex].nextInThread;
- if (nextIndex == -1) break;
- if ((*subjectArray)[nextIndex].partNum != partNum) break;
- index = nextIndex;
- }
- }
- if (index == -1) break;
- if (numArts > 1) {
- sprintf(statusMsg, statusMsgFormat, artNum, numArts, partNum, numPartsToSave);
- } else if (hasParts) {
- sprintf(statusMsg, statusMsgFormat, partNum, numPartsToSave);
- }
- err = DisplayStatusMessage(statusMsg);
- if (err != noErr) goto exit;
- number = (*subjectArray)[index].number;
-
- err = CopyArticleToFile(groupName, number, nil, "ARTICLE", refNum,
- false, false, &partKind);
- if (err != noErr) goto exit;
- if (partKind == kArtNotOnServer) {
- *fileKind = kArtNotOnServer;
- goto exit;
- } else if (*fileKind == kNoAttachedFile) {
- *fileKind = partKind;
- }
- if (!hasParts) break;
- index = (*subjectArray)[index].nextInThread;
-
- }
-
- if (*fileKind != kArtNotOnServer && *fileKind != kNoAttachedFile) {
- if (FindParentCell(wind, threadHeadIndex, &theCell)) {
- MarkSubjectCellRead(wind, theCell);
- if (!(*subjectArray)[threadHeadIndex].collapsed) {
- n = (*subjectArray)[threadHeadIndex].threadLength;
- while (--n > 0) {
- theCell.v++;
- MarkSubjectCellRead(wind, theCell);
- }
- }
- }
- }
-
- exit:
-
- MyFSClose(refNum, GiveTime);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- RunDecodeHelperProgram
-
- Run the helper program to decode the temp file.
-
- Entry: fSpec = pointer to file spec for temp file.
- fileKind = kind of attached binary.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr RunDecodeHelperProgram (FSSpec *fSpec, TAttachedFileKind fileKind)
- {
- OSErr err = noErr;
- FSSpec appSpec, fSpecWithSuffix;
- Boolean running;
- ProcessSerialNumber psn;
- CStr255 fmt, msg;
- char *suffix;
- StringPtr helperName;
-
- helperName = fileKind == kBinHex ? gPrefs.hqxHelperName : gPrefs.uuHelperName;
-
- err = FindAppFromSig(fileKind == kBinHex ? gPrefs.hqxHelper : gPrefs.uuHelper,
- &appSpec, &running, &psn);
- if (err != noErr) goto exit1;
-
- fSpecWithSuffix = *fSpec;
- suffix = fileKind == kBinHex ? ".hqx" : ".uu";
- err = MakeFileNameUnique(&fSpecWithSuffix, suffix);
- if (err != noErr) goto exit3;
-
- err = FSpRename(fSpec, fSpecWithSuffix.name);
- if (err != noErr) goto exit3;
-
- err = LaunchAppWithDoc(running, &appSpec, &psn, &fSpecWithSuffix, 0,
- launchContinue | launchNoFileFlags | launchDontSwitch | launchUseMinimum);
- if (err != noErr) goto exit2;
-
- return noErr;
-
- exit1:
-
- if (err == fnfErr) {
- GetCString(kStrCantFindDecodeHelper, fmt);
- p2cstr(helperName);
- sprintf(msg, fmt, helperName);
- c2pstr((char*)helperName);
- DoCantFindHelperDialog(msg);
- return userCanceledErr;
- } else {
- goto exit3;
- }
-
- exit2:
-
- if (err == memFullErr || err == memFragErr || err == appMemFullErr) {
- GetCString(kStrDecodeHelperNoMem, fmt);
- p2cstr(helperName);
- sprintf(msg, fmt, helperName);
- c2pstr((char*)helperName);
- ErrorMessage(msg);
- return userCanceledErr;
- } else {
- goto exit3;
- }
-
- exit3:
-
- GetCString(kStrDecodeHelperUnexpectedErr, fmt);
- p2cstr(helperName);
- sprintf(msg, fmt, err, helperName);
- c2pstr((char*)helperName);
- ErrorMessage(msg);
- return userCanceledErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ExtractBinaries
-
- Extract binaries for an article or thread.
-
- Entry: wind = pointer to subject window.
- index = index of article or part in subject array.
- artNum = article number being saved (1,2,3,...numArts).
- numArts = total number of articles being saved.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- *fileKind = kind of attached file.
- ----------------------------------------------------------------------------*/
-
- OSErr ExtractBinaries (WindowPtr wind, short index, short artNum,
- short numArts, short modifiers, TAttachedFileKind *fileKind)
- {
- static Str31 fileName;
- static FSSpec fSpec;
- static ScriptCode scriptTag;
- OSErr err = noErr;
-
- MyICReadSharedPrefs(kICeditorHelper);
-
- if (artNum == 1) {
- GetPString(kStrTempFileName, fileName);
- if (gPrefs.savedBinDefaultFolder && (modifiers & optionKey) == 0) {
- err = CheckDownloadFileExists(fileName, &fSpec, &scriptTag);
- if (err != noErr) return err;
- } else {
- err = PresentStandardDownloadSaveFileDialog(fileName, &fSpec, &scriptTag);
- if (err != noErr) return err;
- }
- } else {
- CopyPascalString(fSpec.name, fileName);
- err = MakeFileNameUnique(&fSpec, nil);
- if (err != noErr) return err;
- }
-
- err = SaveBinariesToFile(wind, index, &fSpec, scriptTag, artNum, numArts,
- fileKind);
- if (err != noErr) goto exit;
-
- if (*fileKind == kNoAttachedFile || *fileKind == kArtNotOnServer) {
- FSpDelete(&fSpec);
- return noErr;
- }
-
- err = RunDecodeHelperProgram(&fSpec, *fileKind);
- if (err != noErr) return err;
-
- return noErr;
-
- exit:
-
- FSpDelete(&fSpec);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- TooStupidAlert
-
- Present the "I'm too stupid to extract binaries" alert.
-
- Exit: function result = error code (userCancledErr if alert
- presented with no problems).
- ----------------------------------------------------------------------------*/
-
- static OSErr TooStupidAlert (void)
- {
- OSErr err = noErr;
- DialogPtr dlg;
- short item;
-
- err = MyGetNewDialog(kTooStupidAlert, ok, 0, &dlg);
- if (err != noErr) return err;
- SysBeep(0);
- MyModalDialog(dlg, gDialogFilterUPP, &item);
- err = DoClose(dlg);
- if (err != noErr) return err;
- return userCanceledErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ExtractBinariesForArticleWindow
-
- Extract binaries for an article window.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr ExtractBinariesForArticleWindow (WindowPtr wind, short modifiers)
- {
- TWindow **info;
- OSErr err = noErr;
- TAttachedFileKind fileKind;
-
- info = (TWindow**)GetWRefCon(wind);
-
- if ((**info).parentWindow == nil) return TooStupidAlert();
-
- err = CheckForMissingParts(wind);
- if (err != noErr) return err;
-
- err = ExtractBinaries((**info).parentWindow, (**info).parentSubject,
- 1, 1, modifiers, &fileKind);
- if (err != noErr) return err;
-
- if (fileKind == kNoAttachedFile) {
- NoteMessageNumber(kStrArtHasNoAttachedFile);
- return userCanceledErr;
- }
-
- if (fileKind == kArtNotOnServer) {
- NoteMessageNumber(kStrArtNotOnServer);
- return userCanceledErr;
- }
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ExtractBinariesDragAndDrop
-
- Extract binaries for an article window and the end of a drag
- and drop sequence.
-
- Entry: wind = pointer to article window.
- fSpec = pointer to file spec.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr ExtractBinariesDragAndDrop (WindowPtr wind, FSSpec *fSpec)
- {
- TWindow **info;
- OSErr err = noErr;
- TAttachedFileKind fileKind;
-
- info = (TWindow**)GetWRefCon(wind);
-
- err = CheckForMissingParts(wind);
- if (err != noErr) goto exit;
-
- err = SaveBinariesToFile((**info).parentWindow, (**info).parentSubject,
- fSpec, smSystemScript, 1, 1, &fileKind);
- if (err != noErr) goto exit;
-
- if (fileKind == kNoAttachedFile) {
- NoteMessageNumber(kStrArtHasNoAttachedFile);
- err = userCanceledErr;
- goto exit;
- }
-
- if (fileKind == kArtNotOnServer) {
- NoteMessageNumber(kStrArtNotOnServer);
- return userCanceledErr;
- }
-
- err = RunDecodeHelperProgram(fSpec, fileKind);
- if (err != noErr) return err;
-
- return noErr;
-
- exit:
-
- FSpDelete(fSpec);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CanExtractBinaries
-
- Check to see if we can extract binaries from an article window (it has an
- attached binary file, or it is part 0 of a multiple-part posting).
-
- Entry: wind = pointer to article window.
-
- Exit: function result = true if can extract binaries from this window.
- *iconRect = rect enclosing attached file icon.
- ----------------------------------------------------------------------------*/
-
- static Boolean CanExtractBinaries (WindowPtr wind, Rect *iconRect)
- {
- WindowPtr parent;
- TWindow **info, **parentInfo;
- TSubject **subjectArray;
- Boolean result;
-
- info = (TWindow**)GetWRefCon(wind);
- parent = (**info).parentWindow;
- if ((**info).attachedFile) {
- result = true;
- } else {
- if (parent == nil) {
- result = false;
- } else {
- parentInfo = (TWindow**)GetWRefCon(parent);
- subjectArray = (**parentInfo).subjectArray;
- result = (*subjectArray)[(**info).parentSubject].partNum == 0;
- }
- }
- if (result) {
- if (parent == nil) {
- SetRect(iconRect, wind->portRect.right - 32, 0,
- wind->portRect.right, 32);
-
- } else {
- SetRect(iconRect, wind->portRect.right - 44, 0,
- wind->portRect.right - 12, 32);
- }
- }
- return result;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DragAttachedFileIconSendProc
-
- The Drag Manager send proc for dragging the attached file icon.
-
- Entry: theType = flavor type = 'SPEC'.
- dragSendRefCon = pointer to file spec, with file name
- filled in.
- theItemRef = item reference.
- theDragRef = drag reference.
-
- Exit: function result = error code.
- file spec volume reference number and directory id filled in.
- file created.
- file spec sent to Finder as flavor data.
- ----------------------------------------------------------------------------*/
-
- static pascal OSErr DragAttachedFileIconSendProc (FlavorType theType,
- void *dragSendRefCon, ItemReference theItemRef, DragReference theDragRef)
- {
- AEDesc dropLocation;
- OSErr err = noErr;
- FSSpec *fSpec;
-
- if (DragTargetWasTrash(theDragRef)) return userCanceledErr;
-
- MyICReadSharedPrefs(kICeditorHelper);
-
- fSpec = (FSSpec*)dragSendRefCon;
-
- err = GetDropLocation(theDragRef, &dropLocation);
- if (err != noErr) return err;
-
- err = GetDropLocationDirectory(&dropLocation, &fSpec->vRefNum, &fSpec->parID);
- if (err != noErr) goto exit;
-
- err = MakeFileNameUnique(fSpec, nil);
- if (err != noErr) goto exit;
-
- err = FSpCreate(fSpec, gPrefs.savedArtCreator, 'TEXT', smSystemScript);
- if (err != noErr) goto exit;
-
- err = SetDragItemFlavorData(theDragRef, theItemRef, 'SPEC',
- fSpec, sizeof(FSSpec), 0);
-
- exit:
-
- AEDisposeDesc(&dropLocation);
- return err;
- }
-
-
- /*----------------------------------------------------------------------------
- DragAttachedFileIcon
-
- Handle a mouse down event in the attached file icon of an article
- window when the Drag Manager is present.
-
- Entry: wind = pointer to article window.
- iconRect = pointer to icon rectangle in local coords.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DragAttachedFileIcon (WindowPtr wind, Rect *iconRect, short modifiers)
- {
- OSErr err = noErr;
- DragReference dragRef;
- Boolean haveDragRef = false;
- PromiseHFSFlavor promise;
- RgnHandle dragRgn = nil;
- Rect globalIconRect;
- FSSpec fSpec;
-
- PlotIconID(iconRect, 0, ttSelected, kFileIconID);
- if (WaitMouseMoved(gCurEvent.where)) {
- err = NewDrag(&dragRef);
- if (err != noErr) goto exit;
- MyICReadSharedPrefs(kICeditorHelper);
- haveDragRef = true;
- promise.fileType = 'TEXT';
- promise.fileCreator = gPrefs.savedArtCreator;
- promise.fdFlags = 0;
- promise.promisedFlavor = 'SPEC';
- err = AddDragItemFlavor(dragRef, 1, flavorTypePromiseHFS, &promise,
- sizeof(PromiseHFSFlavor), 0);
- if (err != noErr) goto exit;
- err = AddDragItemFlavor(dragRef, 1, 'SPEC', nil, 0, 0);
- if (err != noErr) goto exit;
- dragRgn = NewRgn();
- globalIconRect = *iconRect;
- LocalToGlobalRect(&globalIconRect);
- err = IconIDToRgn(dragRgn, &globalIconRect, ttNone, kFileIconID);
- if (err != noErr) goto exit;
- OutlineRegion(dragRgn);
- GetPString(kStrTempFileName, fSpec.name);
- err = SetDragSendProc(dragRef, gDragAttachedFileIconSendProcUPP, &fSpec);
- if (err != noErr) goto exit;
- err = TrackDrag(dragRef, &gCurEvent, dragRgn);
- if (err != noErr) goto exit;
- DisposeRgn(dragRgn);
- DisposeDrag(dragRef);
- PlotIconID(iconRect, 0, ttNone, kFileIconID);
- err = ExtractBinariesDragAndDrop(wind, &fSpec);
- if (err != noErr) goto exit;
- } else {
- PlotIconID(iconRect, 0, ttNone, kFileIconID);
- return ExtractBinariesForArticleWindow(wind, modifiers);
- }
- return noErr;
-
- exit:
-
- if (haveDragRef) DisposeDrag(dragRef);
- if (dragRgn != nil) DisposeRgn(dragRgn);
- PlotIconID(iconRect, 0, ttNone, kFileIconID);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Find
-
- Search an article window for a pattern.
-
- Entry: wind = pointer to article window.
- offset = offset into currently displayed text section
- to begin search, or -1 to start search at beginning.
- gFindPattern = pattern.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Find (WindowPtr wind, long offset)
- {
- TWindow **info;
- Handle fullText;
- TEHandle theTE;
- short curSection, numSections, newSection;
- long **breaks;
- char state;
- long matchOffset, len;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- fullText = (**info).fullText;
- curSection = (**info).curSection;
- numSections = (**info).numSections;
- breaks = (**info).sectionBreaks;
-
- if (offset == -1) {
- offset = 0;
- if (!(**info).showDetails) offset += FindBody(fullText);
- } else {
- if (curSection == 0 && !(**info).showDetails)
- offset += FindBody(fullText);
- offset += (*breaks)[curSection];
- }
- len = (*breaks)[numSections] - offset;
-
- state = MyHGetState(fullText);
- MyHLock(fullText);
- err = MyNSubstringSearch(*fullText + offset, gFindPattern, len,
- &matchOffset, GiveTime);
- MyHSetState(fullText, state);
- if (err != noErr) return err;
- if (matchOffset == -1) {
- SysBeep(0);
- } else {
- offset += matchOffset;
- newSection = 0;
- while (offset >= (*breaks)[newSection+1]) newSection++;
- offset -= (*breaks)[newSection];
- if (newSection != curSection) {
- SetControlValue((**info).hScroll, newSection);
- ScrollSection(wind, curSection - newSection);
- }
- if (newSection == 0 && !(**info).showDetails)
- offset -= FindBody(fullText);
- theTE = (**info).theTE;
- TESetSelect(offset, offset + strlen(gFindPattern), theTE);
- TEScrollScrollToMiddle(theTE, offset, (**info).vScroll);
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoSave
-
- Handle the "Save" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoSave (WindowPtr wind, short modifiers)
- {
- Str31 fileName;
- FSSpec fSpec;
- ScriptCode scriptTag;
- Boolean append = false;
- OSErr err = noErr;
- TWindow **info;
- Boolean saveEncodedText, saveThreadsToSeparateFiles;
-
- info = (TWindow**)GetWRefCon(wind);
- saveEncodedText = gPrefs.saveEncodedText;
- saveThreadsToSeparateFiles = gPrefs.saveThreadsToSeparateFiles;
- FormFileName(wind, fileName);
- if (gPrefs.savedArtDefaultFolder && (modifiers & optionKey) == 0) {
- err = CheckArticleFileExists(fileName, &fSpec, &scriptTag, &append,
- &saveEncodedText, &saveThreadsToSeparateFiles);
- if (err != noErr) return err;
- } else {
- err = PresentStandardArticleSaveFileDialog(fileName, &fSpec, &scriptTag,
- &saveEncodedText, &saveThreadsToSeparateFiles);
- if (err != noErr) return err;
- }
- return SaveArticleWindToFile(wind, modifiers, &fSpec, scriptTag, append,
- saveEncodedText);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoSaveAs
-
- Handle the "Save As" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoSaveAs (WindowPtr wind, short modifiers)
- {
- Str31 fileName;
- FSSpec fSpec;
- ScriptCode scriptTag;
- OSErr err = noErr;
- TWindow **info;
- Boolean saveEncodedText, saveThreadsToSeparateFiles;
-
- info = (TWindow**)GetWRefCon(wind);
- saveEncodedText = gPrefs.saveEncodedText;
- saveThreadsToSeparateFiles = gPrefs.saveThreadsToSeparateFiles;
- FormFileName(wind, fileName);
- err = PresentStandardArticleSaveFileDialog(fileName, &fSpec,
- &scriptTag, &saveEncodedText, &saveThreadsToSeparateFiles);
- if (err != noErr) return err;
- return SaveArticleWindToFile(wind, modifiers, &fSpec, scriptTag, false,
- saveEncodedText);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoPrint
-
- Handle the "Print" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoPrint (WindowPtr wind, short modifiers)
- {
- TWindow **info;
- TEHandle theTE;
- Handle text, fullText;
- CStr255 subject, from, str;
- OSErr err = noErr;
- long start, end;
-
- info = (TWindow**)GetWRefCon(wind);
- fullText = (**info).fullText;
- theTE = (**info).theTE;
- start = (**theTE).selStart;
- end = (**theTE).selEnd;
-
- err = StartPrint();
- if (err != noErr) return err;
-
- err = DisplayStatusMessageNumber(kStrPrinting);
- if (err != noErr) return err;
-
- FindHeaderCString(fullText, "Subject", subject, sizeof(subject));
- if (FindHeaderCString(fullText, "From", from, sizeof(from))) {
- FormatAuthorName(from);
- sprintf(str, "%.40s, %.100s", from, subject);
- } else {
- strcpy(str, subject);
- }
-
- if ((modifiers & shiftKey) == 0 || start >= end) {
- text = fullText;
- start = 0;
- end = MyGetHandleSize(text);
- } else {
- text = (**theTE).hText;
- }
-
- return PrintText(text, start, end, str);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoAppend
-
- Handle the "Append" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoAppend (WindowPtr wind, short modifiers)
- {
- FSSpec fSpec;
- OSErr err = noErr;
- TWindow **info;
- Boolean saveEncodedText;
-
- info = (TWindow**)GetWRefCon(wind);
- saveEncodedText = gPrefs.saveEncodedText;
- err = PresentStandardArticleGetFileDialog(&fSpec, &saveEncodedText);
- if (err != noErr) return err;
- return SaveArticleWindToFile(wind, modifiers, &fSpec, smSystemScript, true,
- saveEncodedText);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoCopy
-
- Handle the "Copy" command.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void DoCopy (WindowPtr wind)
- {
- TWindow **info;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- MyTECopy(theTE);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoSelectAll
-
- Handle the "Select All" command.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void DoSelectAll (WindowPtr wind)
- {
- TWindow **info;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- TESetSelect(0, 0x7fff, theTE);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoFind
-
- Handle the "Find" command for an article window.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoFind (WindowPtr wind)
- {
- TWindow **info;
- OSErr err = noErr;
- TEHandle theTE;
-
- err = DoFindDialog();
- if (err != noErr) return err;
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- return Find(wind, gPrefs.startFindAtBeginning ? -1 : (**theTE).selStart);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoFindAgain
-
- Handle the "Find Again" command for an article window.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoFindAgain (WindowPtr wind)
- {
- TWindow **info;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- return Find(wind, (**theTE).selEnd);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoEnterSelection
-
- Handle the "Enter Selection" command for an article window.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoEnterSelection (WindowPtr wind)
- {
- TWindow **info;
- TEHandle theTE;
- short selStart, selEnd, len;
- Handle hText;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- selStart = (**theTE).selStart;
- selEnd = (**theTE).selEnd;
- hText = (**theTE).hText;
- if (selStart >= selEnd || selEnd > selStart + 255) return noErr;
- len = selEnd - selStart;
- BlockMoveData(*hText + selStart, gFindPattern, len);
- gFindPattern[len] = 0;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoShowHideDetails
-
- Handle the "Show/Hide Details" command.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoShowHideDetails (WindowPtr wind)
- {
- TWindow **info;
- Boolean showDetails;
- short curSection;
- TEHandle theTE;
- Handle text;
- long **breaks;
- long length, offset;
- Rect textRect;
- OSErr err = noErr;
- char state;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- showDetails = (**info).showDetails = !(**info).showDetails;
- SetEditMenuShowHideDetails(!showDetails);
- curSection = (**info).curSection;
- breaks = (**info).sectionBreaks;
- GetTextRect(wind, &textRect);
-
- if (curSection != 0) ScrollActionSection((**info).hScroll, kScrollToHome);
- TEScrollScrollByPartCode(theTE, (**info).vScroll, kScrollToHome);
-
- text = (**info).fullText;
- offset = 0;
- length = (*breaks)[1];
- if (!showDetails) {
- offset = FindBody(text);
- if (offset > length) offset = length;
- length -= offset;
- }
- state = MyHGetState(text);
- MyHLock(text);
- err = MyTESetText(*text + offset, length, theTE);
- MyHSetState(text, state);
- if (err != noErr) return err;
- TESetSelect(0, 0, theTE);
- TEScrollAdjustScrollMax(theTE, (**info).vScroll);
- InvalRect(&textRect);
-
- if (showDetails && gPrefs.reZoomWindows &&
- GetControlMaximum((**info).vScroll) > 0 && !(**info).windPosLocked)
- {
- err = DoZoom(wind, inZoomOut);
- if (err != noErr) return err;
- } else {
- SetWindowNeedsZooming(wind);
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoRot13
-
- Handle the "Rot13" command.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void DoRot13 (WindowPtr wind)
- {
- TWindow **info;
- TEHandle theTE;
- Rect r;
- short selStart, selEnd, curSection;
- Boolean showDetails;
- Handle hText, text;
- long **breaks;
- long offset;
-
- info = (TWindow**)GetWRefCon(wind);
- showDetails = (**info).showDetails;
- theTE = (**info).theTE;
- curSection = (**info).curSection;
- text = (**info).fullText;
- breaks = (**info).sectionBreaks;
- selStart = (**theTE).selStart;
- selEnd = (**theTE).selEnd;
- if (selStart >= selEnd) {
- selStart = 0;
- selEnd = (**theTE).teLength;
- }
- hText = (**theTE).hText;
- offset = curSection == 0 ? 0 : (*breaks)[curSection];
-
- Rot13Text(hText, selStart, selEnd);
- r = (**theTE).viewRect;
- InvalRect(&r);
-
- if (curSection == 0 && !showDetails) offset += FindBody(text);
- BlockMoveData(*hText + selStart, *text + offset + selStart, selEnd - selStart);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoReply
-
- Handle the "Reply" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoReply (WindowPtr wind, short modifiers)
- {
- TWindow **info;
- Handle text, quoteText;
- long start, end;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- text = (**info).fullText;
-
- if ((modifiers & shiftKey) == 0) {
- quoteText = nil;
- } else {
- theTE = (**info).theTE;
- quoteText = (**theTE).hText;
- start = (**theTE).selStart;
- end = (**theTE).selEnd;
- }
-
- return OpenReplyWindow(text, quoteText, start, end, (modifiers & optionKey) != 0);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoForward
-
- Handle the "Forward" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoForward (WindowPtr wind, short modifiers)
- {
- TWindow **info;
- Handle text, quoteText;
- long start, end;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- text = (**info).fullText;
-
- if ((modifiers & shiftKey) == 0) {
- quoteText = nil;
- } else {
- theTE = (**info).theTE;
- quoteText = (**theTE).hText;
- start = (**theTE).selStart;
- end = (**theTE).selEnd;
- }
-
- return OpenForwardWindow(text, quoteText, start, end, (modifiers & optionKey) != 0);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoRedirect
-
- Handle the "Redirect" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoRedirect (WindowPtr wind, short modifiers)
- {
- TWindow **info;
- Handle text, quoteText;
- long start, end;
- TEHandle theTE;
-
- info = (TWindow**)GetWRefCon(wind);
- text = (**info).fullText;
-
- if ((modifiers & shiftKey) == 0) {
- quoteText = nil;
- } else {
- theTE = (**info).theTE;
- quoteText = (**theTE).hText;
- start = (**theTE).selStart;
- end = (**theTE).selEnd;
- }
-
- return OpenRedirectWindow(text, quoteText, start, end, (modifiers & optionKey) != 0);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoExtractBinaries
-
- Handle the "Extract Binaries" command.
-
- Entry: wind = pointer to article window.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoExtractBinaries (WindowPtr wind, short modifiers)
- {
- return ExtractBinariesForArticleWindow(wind, modifiers);
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoOpenAllReferences
-
- Handle the "Open all References" command.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoOpenAllReferences (WindowPtr wind)
- {
- WindowPtr newWind;
- TWindow **info;
- Handle fullText, references = nil;
- CStr255 msgId;
- short totalRefs = 0, totalOpenedRefs = 0;
- char *p, *q;
- long len;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- fullText = (**info).fullText;
-
- err = FindHeaderHandle(fullText, "References", &references);
- if (err != noErr) goto exit;
- if (references == nil) {
- NoteMessageNumber(kStrNoRefs);
- return noErr;
- }
-
- MyHLock(references);
- q = *references + MyGetHandleSize(references) - 1;
- while (q >= *references) {
- while (*q != '>' && q >= *references) q--;
- p = q-1;
- while (*p != '<' && p >= *references) p--;
- len = q - p + 1;
- q = p - 1;
- if (len <= 2 || len > 255) continue;
- BlockMoveData(p, msgId, len);
- *(msgId + len) = 0;
- totalRefs++;
- if (CheckAlreadyOpen(msgId)) {
- totalOpenedRefs++;
- } else {
- err = GetArticleAndMakeNewWindow(nil, 0, nil, 0, msgId, nil, false, nil, true,
- &newWind);
- if (err != noErr) goto exit;
- if (newWind != nil) {
- totalOpenedRefs++;
- MyShowWindow(newWind);
- }
- }
- }
- MyDisposeHandle(references);
-
- if (totalOpenedRefs < totalRefs) {
- if (totalOpenedRefs == 0) {
- NoteMessageNumber(kStrNoneOpened);
- } else {
- NoteMessageNumber(kStrSomeNotOpened);
- }
- }
- return noErr;
-
- exit:
-
- MyDisposeHandle(references);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoCancelArticle
-
- Handles the "Cancel Article" command.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoCancelArticle (WindowPtr wind)
- {
- TWindow **info;
- Handle text;
- Handle groups = nil;
- CStr255 idStr, statusMsg;
- OSErr err = noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- text = (**info).fullText;
- if (!UserIsPoster(text)) goto exit1;
-
- GetCString(kStrCancelingStatusMsg, statusMsg);
- err = DisplayStatusMessage(statusMsg);
- if (err != noErr) return err;
-
- if (!FindHeaderCString(text, "Message-ID", idStr, sizeof(idStr))) goto exit2;
-
- err = FindHeaderHandle(text, "Newsgroups", &groups);
- if (err != noErr) goto exit3;
- if (groups == nil) goto exit4;
-
- err = CancelArticle(idStr, groups, statusMsg);
- if (err != noErr) goto exit3;
-
- MyDisposeHandle(groups);
- return noErr;
-
- exit1:
-
- MyDisposeHandle(groups);
- ErrorMessageNumber(kStrNotCanceled);
- return userCanceledErr;
-
- exit2:
-
- MyDisposeHandle(groups);
- ErrorMessageNumber(kStrNoMsgID);
- return userCanceledErr;
-
- exit3:
-
- MyDisposeHandle(groups);
- return err;
-
- exit4:
-
- MyDisposeHandle(groups);
- ErrorMessageNumber(kStrNoNewsgroupsHeader);
- return userCanceledErr;
- }
-
-
-
-
- /*----------------------------------------------------------------------------
- Activate
-
- Handle an activate event for an article window.
-
- Entry: wind = pointer to article window.
- act = true to activate, false to deactivate
- ----------------------------------------------------------------------------*/
-
- static void Activate (WindowPtr wind, Boolean act)
- {
- TWindow **info;
- TEHandle theTE;
- ControlHandle vScroll, hScroll;
- Rect r;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- vScroll = (**info).vScroll;
- hScroll = (**info).hScroll;
- if (act) {
- ShowControl(vScroll);
- if (hScroll != nil) ShowControl(hScroll);
- TEActivate(theTE);
- } else {
- HideControl(vScroll);
- if (hScroll != nil) HideControl(hScroll);
- TEDeactivate(theTE);
- }
- r = wind->portRect;
- r.top = r.bottom - 15;
- r.left = r.right - 15;
- InvalRect(&r);
- }
-
-
-
- /*----------------------------------------------------------------------------
- Update
-
- Handle an update event for an article window.
-
- Entry: wind = pointer to article window.
- ----------------------------------------------------------------------------*/
-
- static void Update (WindowPtr wind)
- {
- TWindow **info, **parentInfo;
- short panelHeight, windWidth, lineHeight;
- Rect r;
- TEHandle theTE;
- WindowPtr parent;
- TSubject subject, **subjectArray;
- Handle fullText;
- CStr255 from, organization, date, newsgroups;
- CStr255 followupto, replyto;
- CStr255 articleXofYFormat;
- char msg[600];
- FontInfo fontInfo;
- short len, threadInfoWidth, v;
- char c;
- Rect iconRect;
- short maxPanelStringWidth;
-
- info = (TWindow**)GetWRefCon(wind);
- panelHeight = (**info).panelHeight;
- theTE = (**info).theTE;
- fullText = (**info).fullText;
- GetFontInfo(&fontInfo);
- lineHeight = fontInfo.leading + fontInfo.ascent + fontInfo.descent;
- if (lineHeight < 11) lineHeight = 11;
-
- r = wind->portRect;
- r.top += panelHeight;
- ClipRect(&r);
- DrawGrowIcon(wind);
- ClipRect(&wind->portRect);
-
- UpdateControls(wind, wind->visRgn);
-
- windWidth = wind->portRect.right - wind->portRect.left;
- MoveTo(0, panelHeight-3);
- LineTo(windWidth, panelHeight-3);
- MoveTo(0, panelHeight-1);
- LineTo(windWidth, panelHeight-1);
-
- if (CanExtractBinaries(wind, &iconRect)) {
- PlotIconID(&iconRect, 0, ttNone, kFileIconID);
- maxPanelStringWidth = iconRect.left - 20;
- } else if ((**info).parentWindow != nil) {
- maxPanelStringWidth = windWidth - 40;
- } else {
- maxPanelStringWidth = windWidth - 20;
- }
-
- if ((**info).parentWindow != nil) DrawArrowPair((**info).nextPrevArrowPair);
-
- FindHeaderCString(fullText, "From", from, sizeof(from));
- GetCString(kStrFrom, msg);
- strcat(msg, from);
- v = fontInfo.ascent + 3;
- DrawPanelString(msg, v, maxPanelStringWidth);
-
- FindHeaderCString(fullText, "Organization", organization, sizeof(organization));
- GetCString(kStrOrg, msg);
- strcat(msg, organization);
- v += lineHeight;
- DrawPanelString(msg, v, maxPanelStringWidth);
-
- FindHeaderCString(fullText, "NewsGroups", newsgroups, sizeof(date));
- GetCString(kStrNewsgroups, msg);
- strcat(msg, newsgroups);
- v += lineHeight;
- DrawPanelString(msg, v, maxPanelStringWidth);
-
- if ((**info).showFollowupTo) {
- FindHeaderCString(fullText, "Followup-To", followupto, sizeof(followupto));
- GetCString(kStrFollowupto, msg);
- strcat(msg, followupto);
- v += lineHeight;
- DrawPanelString(msg, v, maxPanelStringWidth);
- }
-
- if ((**info).showReplyTo) {
- FindHeaderCString(fullText, "Reply-To", replyto, sizeof(replyto));
- GetCString(kStrReplyto, msg);
- strcat(msg, replyto);
- v += lineHeight;
- DrawPanelString(msg, v, maxPanelStringWidth);
- }
-
- v += lineHeight;
- threadInfoWidth = 0;
- parent = (**info).parentWindow;
- if (parent != nil) {
- parentInfo = (TWindow**)GetWRefCon(parent);
- subjectArray = (**parentInfo).subjectArray;
- subject = (*subjectArray)[(**info).parentSubject];
- if (subject.threadLength > 1) {
- c = subject.threadOrdinal == subject.threadLength ? '•' : '…';
- GetCString(kStrArticleXofY, articleXofYFormat);
- sprintf(msg, articleXofYFormat, subject.threadOrdinal, subject.threadLength, c);
- len = strlen(msg);
- threadInfoWidth = TextWidth(msg, 0, len);
- MoveTo(windWidth - 10 - threadInfoWidth, v);
- DrawText(msg, 0, len);
- }
- }
- (**info).threadInfoWidth = threadInfoWidth;
-
- FindHeaderCString(fullText, "Date", date, sizeof(date));
- Cleanup822Date(date);
- GetCString(kStrDate, msg);
- strcat(msg, date);
- DrawPanelString(msg, v, windWidth-20-threadInfoWidth);
-
- if ((**info).numSections > 1) DrawSectionMessage(wind);
-
- TEUpdate(&wind->portRect, theTE);
-
- DrawPadlockIcon(wind);
- }
-
-
-
- /*----------------------------------------------------------------------------
- Mouse
-
- Handle a mouse down event in the content area of an article window.
-
- Entry: wind = pointer to article window.
- where = location of mouse down in local coords.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Mouse (WindowPtr wind, Point where, short modifiers)
- {
- TWindow **info;
- TEHandle theTE;
- Rect viewRect, iconRect;
- short part, oldVal, dv,dh;
- ControlHandle control, vScroll, hScroll;
- OSErr err = noErr;
- Boolean dragged = false, trashed;
- short oldSelStart, oldSelEnd, trackArrowPairResult;
- Boolean Draggable (WindowPtr wind, Point where, short modifiers);
-
- if (HandlePadlockClick(wind, where, &gPrefs.articleWindPosLocked,
- &gPrefs.articleWindLocn)) return noErr;
-
- info = (TWindow**) GetWRefCon(wind);
- theTE = (**info).theTE;
- vScroll = (**info).vScroll;
- hScroll = (**info).hScroll;
-
- if ((**info).sectionArrowPair != nil) {
- trackArrowPairResult = TrackArrowPair((**info).sectionArrowPair);
- if (trackArrowPairResult == -1) {
- ScrollActionSection(hScroll, inUpButton);
- return noErr;
- } else if (trackArrowPairResult == +1) {
- ScrollActionSection(hScroll, inDownButton);
- return noErr;
- }
- }
-
- if ((**info).nextPrevArrowPair != nil) {
- trackArrowPairResult = TrackArrowPair((**info).nextPrevArrowPair);
- if (trackArrowPairResult != 0) {
- return GoBackwardsOrForwardsOneArticle(wind, trackArrowPairResult);
- }
- }
-
- viewRect = (**theTE).viewRect;
- InsetRect(&viewRect, -kTextMargin, 0);
- part = FindControl(where, wind, &control);
- if (part != 0) {
- if (control == vScroll) {
- if (part == inThumb) {
- oldVal = GetControlValue(vScroll);
- TrackControl(vScroll, where, nil);
- dv = GetControlValue(vScroll) - oldVal;
- if (dv != 0) TEScrollScrollText(theTE, vScroll, -dv);
- } else {
- SetControlReference(vScroll, 0);
- TrackControl(vScroll, where, gScrollActionUPP);
- SetControlReference(vScroll, 1);
- TEScrollAdjustScrollMax(theTE, vScroll);
- }
- } else if (control == hScroll) {
- if (part == inThumb) {
- oldVal = GetControlValue(hScroll);
- TrackControl(hScroll, where, nil);
- dh = GetControlValue(hScroll) - oldVal;
- if (dh != 0) ScrollSection(wind, -dh);
- } else {
- TrackControl(hScroll, where, gScrollActionSectionUPP);
- }
- }
- } else if (PtInRect(where, &viewRect)) {
- if (gHaveDragMgr) {
- err = DragText(&gCurEvent, where, theTE, &dragged, &trashed);
- if (err != noErr) return err;
- }
- if (wind == FrontWindow() && !dragged) {
- oldSelStart = (**theTE).selStart;
- oldSelEnd = (**theTE).selEnd;
- MyTEClick(where, (modifiers & shiftKey) != 0, theTE);
- err = CommandClick(wind, theTE, oldSelStart, oldSelEnd, modifiers);
- if (err != noErr) return err;
- }
- } else if (CanExtractBinaries(wind, &iconRect) && PtInRect(where, &iconRect) &&
- Draggable(wind, where, 0))
- {
- if (gHaveDragMgr) {
- if ((**info).parentWindow == nil) return TooStupidAlert();
- return DragAttachedFileIcon(wind, &iconRect, modifiers);
- } else if (TrackIconClick(where, &iconRect, nil, kFileIconID)) {
- return ExtractBinariesForArticleWindow(wind, modifiers);
- }
- }
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Draggable
-
- Determine whether a mouse down event is on a draggable object in an
- article window.
-
- Entry: wind = pointer to article window.
- where = location of mouse down event, in local coordinates.
- modifiers = modifiers field from event record.
-
- Exit: function result = true if object is draggable.
- ----------------------------------------------------------------------------*/
-
- static Boolean Draggable (WindowPtr wind, Point where, short modifiers)
- {
- Rect iconRect;
- RgnHandle iconRgn;
- OSErr err = noErr;
- Boolean result;
- TWindow **info;
- TEHandle theTE;
-
- if (CanExtractBinaries(wind, &iconRect)) {
- iconRgn = NewRgn();
- err = IconIDToRgn(iconRgn, &iconRect, ttNone, kFileIconID);
- result = err == noErr && PtInRgn(where, iconRgn);
- DisposeRgn(iconRgn);
- if (result) return true;
- }
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- return PtInTEHiliteRgn(where, theTE);
- }
-
-
-
- /*----------------------------------------------------------------------------
- Key
-
- Handle a key down event for an article window.
-
- Entry: wind = pointer to article window.
- theChar = ASCII code of key.
- theKey = keyboard code of key.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Key (WindowPtr wind, unsigned char theChar, unsigned char theKey,
- short modifiers)
- {
- TWindow **info;
- ControlHandle vScroll, hScroll;
- TEHandle theTE;
- OSErr err = noErr;
- short scrollIntoView;
- TKeypadKey keypadKey;
- Boolean isArrow, first, last;
-
- info = (TWindow**)GetWRefCon(wind);
- vScroll = (**info).vScroll;
- hScroll = (**info).hScroll;
- theTE = (**info).theTE;
- isArrow = IsArrowKey(theChar);
-
- if ((modifiers & cmdKey) != 0 && !isArrow) {
- if ((**info).parentWindow != nil) {
- CheckFirstLastArticle(wind, &first, &last);
- if (theChar == '1') {
- if (first) {
- SysBeep(0);
- return noErr;
- }
- return GoBackwardsOrForwardsOneArticle(wind, -1);
- } else if (theChar == '2') {
- if (last) {
- SysBeep(0);
- return noErr;
- }
- return GoBackwardsOrForwardsOneArticle(wind, +1);
- }
- }
- SysBeep(0);
- return noErr;
- }
-
- if (gPrefs.keypadShortcuts && IsKeypadKey(theChar, theKey, &keypadKey)) {
- switch (keypadKey) {
- case kKeypadEqualKey:
- DoSelectAll(wind);
- return noErr;
- case kKeypadStarKey:
- return DoClose(wind);
- case kKeypadMinusKey:
- return DoMarkCommand(wind, false);
- case kKeypadPlusKey:
- return DoMarkCommand(wind, true);
- case kKeypadEnterKey:
- return DoNextGroup(wind);
- case kKeypadPeriodKey:
- return DoNextThread(wind);
- case kKeypad0Key:
- return DoNextArticle(wind);
- case kKeypad1Key:
- TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
- return noErr;
- case kKeypad2Key:
- TEScrollScrollByPartCode(theTE, vScroll, inDownButton);
- return noErr;
- case kKeypad3Key:
- TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
- return noErr;
- case kKeypad4Key:
- if (hScroll != nil) {
- ScrollActionSection(hScroll, inUpButton);
- } else {
- SysBeep(0);
- }
- return noErr;
- case kKeypad5Key:
- if (GetControlValue(vScroll) < GetControlMaximum(vScroll)) {
- TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
- } else if (hScroll != nil &&
- GetControlValue(hScroll) < GetControlMaximum(hScroll))
- {
- ScrollActionSection(hScroll, inDownButton);
- } else {
- return DoNextArticle(wind);
- }
- return noErr;
- case kKeypad6Key:
- if (hScroll != nil) {
- ScrollActionSection(hScroll, inDownButton);
- } else {
- SysBeep(0);
- }
- return noErr;
- case kKeypad7Key:
- TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
- return noErr;
- case kKeypad8Key:
- TEScrollScrollByPartCode(theTE, vScroll, inUpButton);
- return noErr;
- case kKeypad9Key:
- TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
- return noErr;
- default:
- SysBeep(0);
- return noErr;
- }
- }
-
- if (theChar == pageUpKey) {
- TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
- return noErr;
- }
- if (theChar == pageDownKey) {
- TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
- return noErr;
- }
- if (theChar == homeKey) {
- TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
- return noErr;
- }
- if (theChar == endKey) {
- TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
- return noErr;
- }
-
- if (isArrow) {
- TEArrowKey(theChar, modifiers, theTE, 0, &gPrevEvent, &scrollIntoView);
- TEScrollScrollRangeIntoView(theTE, scrollIntoView, scrollIntoView, vScroll);
- return noErr;
- }
-
- if (gPrefs.keyboardShortcuts) {
-
- if (theChar == ' ') {
- if (GetControlValue(vScroll) < GetControlMaximum(vScroll)) {
- TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
- } else if (hScroll != nil && GetControlValue(hScroll) < GetControlMaximum(hScroll)) {
- ScrollActionSection(hScroll, inDownButton);
- } else {
- return DoNextArticle(wind);
- }
- return noErr;
- }
-
- theChar = tolower(theChar);
-
- if (theChar == 'n' || theChar == 'i') {
- return DoNextArticle(wind);
- }
-
- if (theChar == 't') {
- return DoNextThread(wind);
- }
- if (theChar == 'g' || theChar == 'j') {
- return DoNextGroup(wind);
- }
-
- if (theChar == 'w') {
- return DoClose(wind);
- }
-
- if (theChar == 'u') {
- return DoMarkCommand(wind, false);
- }
-
- if (theChar == 'm') {
- return DoMarkCommand(wind, true);
- }
-
- if (theChar == 'a') {
- DoSelectAll(wind);
- return noErr;
- }
-
- }
-
- SysBeep(0);
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Grow
-
- Handle a mouse down event in the grow box of an article window.
-
- Entry: wind = pointer to article window.
- where = location of mouse down event, in global coordinates.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Grow (WindowPtr wind, Point where)
- {
- Rect sizeRect;
- long size;
- short width, height;
-
- SetRect(&sizeRect, kMinWindowWidth, MinHeight(wind), 0x7fff, 0x7fff);
- size = GrowWindow(wind, where, &sizeRect);
-
- if (size != 0) {
- width = LoWord(size);
- height = HiWord(size);
- FixHeight(wind, &height);
- SizeWindow(wind, width, height, false);
- ResizeContents(wind);
- }
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Zoom
-
- Zoom an article window.
-
- Entry: wind = pointer to article window.
- zoomDir = zoom direction = inZoomIn, inZoomOut, or
- zoomOutOnlyIfBigger.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Zoom (WindowPtr wind, short zoomDir)
- {
- TWindow **info;
- short width, height, lineHeight, minHeight, lineWidth, maxWidth, maxBodyLineWidth;
- Rect zoomRect, r;
- WStateData **wState;
- FontInfo fInfo;
- TEHandle theTE, tempTE = nil;
- Handle fullText;
- long numBodyLines, longHeight, offset, length, maxHeight;
- char *p, *pEnd, *lineStart;
- long **breaks;
- short numSections, i;
- OSErr err = noErr;
- char state;
-
- wState = (WStateData**)((WindowPeek)wind)->dataHandle;
- if (zoomDir == inZoomOut || zoomDir == zoomOutOnlyIfBigger) {
- info = (TWindow**)GetWRefCon(wind);
- GetFontInfo(&fInfo);
- lineHeight = fInfo.leading + fInfo.ascent + fInfo.descent;
- theTE = (**info).theTE;
- fullText = (**info).fullText;
- maxBodyLineWidth = (**info).maxBodyLineWidth;
- numBodyLines = (**info).numBodyLines;
-
- if (maxBodyLineWidth == 0) {
- maxWidth = 80 * fInfo.widMax;
- numBodyLines = 0;
- state = MyHGetState(fullText);
- MyHLock(fullText);
- for (p = *fullText + FindBody(fullText),
- pEnd = *fullText + MyGetHandleSize(fullText);
- p < pEnd;
- p++)
- {
- lineStart = p;
- while (p < pEnd && *p != CR) p++;
- numBodyLines++;
- if (maxBodyLineWidth < maxWidth) {
- lineWidth = TextWidth(lineStart, 0, p - lineStart);
- if (lineWidth > maxBodyLineWidth) maxBodyLineWidth = lineWidth;
- }
- }
- MyHSetState(fullText, state);
- if (maxBodyLineWidth > maxWidth) maxBodyLineWidth = maxWidth;
- (**info).maxBodyLineWidth = maxBodyLineWidth;
- (**info).numBodyLines = numBodyLines;
- }
- width = maxBodyLineWidth + 2*kTextMargin + 18;
- if (width < kMinWindowWidth) width = kMinWindowWidth;
-
- if (numBodyLines > 100) {
- height = 0x7fff;
- } else {
- CalculateZoomRect(wind, width, 0x7fff, &zoomRect, gPrefs.dontCoverFinderIcons);
- SetRect(&r, 0, 0, zoomRect.right - zoomRect.left - 15 - 2*kTextMargin, 0x7fff);
- tempTE = TENew(&r, &r);
- breaks = (**info).sectionBreaks;
- numSections = (**info).numSections;
- maxHeight = 0;
- for (i = 0; i < numSections; i++) {
- offset = (*breaks)[i];
- length = (*breaks)[i+1] - offset;
- if (i == 0 && !(**info).showDetails) {
- offset = FindBody(fullText);
- if (offset > length) offset = length;
- length -= offset;
- }
- state = MyHGetState(fullText);
- MyHLock(fullText);
- err = MyTESetText(*fullText + offset, length, tempTE);
- MyHSetState(fullText, state);
- if (err != noErr) goto exit;
- longHeight = (long)TEScrollNumTELines(tempTE) * (long)lineHeight;
- longHeight += (**info).panelHeight + 15 + 2*kTextMargin;
- if (longHeight > maxHeight) maxHeight = longHeight;
- }
- TEDispose(tempTE);
- if (maxHeight > 0x7fff) {
- height = 0x7fff;
- } else {
- height = maxHeight;
- minHeight = MinHeight(wind);
- if (height < minHeight) height = minHeight;
- }
- }
-
- if (zoomDir == zoomOutOnlyIfBigger) {
- if (width <= wind->portRect.right && height <= wind->portRect.bottom) {
- SetWindowNeedsZooming(wind);
- return noErr;
- }
- if (width < wind->portRect.right) width = wind->portRect.right;
- if (height < wind->portRect.bottom) height = wind->portRect.bottom;
- }
-
- CalculateZoomRect(wind, width, height, &zoomRect, gPrefs.dontCoverFinderIcons);
- height = zoomRect.bottom - zoomRect.top;
- FixHeight(wind, &height);
- zoomRect.bottom = zoomRect.top + height;
- (**wState).stdState = zoomRect;
- if (WindRectEqualRect(wind, &zoomRect)) return noErr;
- }
-
- EraseRect(&wind->portRect);
- ZoomWindow(wind, zoomDir, false);
- ResizeContents(wind);
- return noErr;
-
- exit:
-
- if (tempTE != nil) TEDispose(tempTE);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Command
-
- Handle a command for an article window.
-
- Entry: wind = pointer to article window.
- menu = the menu.
- item = the item.
- modifiers = modifiers field from event record.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Command (WindowPtr wind, short menu, short item, short modifiers)
- {
- OSErr err = noErr;
-
- switch (menu) {
-
- case kFileMenu:
-
- switch (item) {
- case kSaveItem:
- err = DoSave(wind, modifiers);
- break;
- case kSaveAsItem:
- err = DoSaveAs(wind, modifiers);
- break;
- case kAppendItem:
- err = DoAppend(wind, modifiers);
- break;
- case kPrintItem:
- err = DoPrint(wind, modifiers);
- break;
- }
- break;
-
- case kEditMenu:
-
- switch (item) {
- case kCopyItem:
- DoCopy(wind);
- break;
- case kSelectAllItem:
- DoSelectAll(wind);
- break;
- case kFindItem:
- err = DoFind(wind);
- break;
- case kFindAgainItem:
- err = DoFindAgain(wind);
- break;
- case kEnterSelectionItem:
- err = DoEnterSelection(wind);
- break;
- case kShowHideDetailsItem:
- err = DoShowHideDetails(wind);
- break;
- case kRot13Item:
- DoRot13(wind);
- break;
- }
- break;
-
- case kNewsMenu:
-
- switch (item) {
- case kNextArticleItem:
- err = DoNextArticle(wind);
- break;
- case kNextThreadItem:
- err = DoNextThread(wind);
- break;
- case kNextGroupItem:
- err = DoNextGroup(wind);
- break;
- case kMarkReadItem:
- err = DoMarkCommand(wind, true);
- break;
- case kMarkUnreadItem:
- err = DoMarkCommand(wind, false);
- break;
- case kReplyItem:
- err = DoReply(wind, modifiers);
- break;
- case kForwardItem:
- err = DoForward(wind, modifiers);
- break;
- case kRedirectItem:
- err = DoRedirect(wind, modifiers);
- break;
- }
- break;
-
- case kSpecialMenu:
- switch (item) {
- case kExtractBinariesItem:
- err = DoExtractBinaries(wind, modifiers);
- break;
- case kSearchItem:
- err = DoSearch(wind);
- break;
- case kOpenAllReferencesItem:
- err = DoOpenAllReferences(wind);
- break;
- case kCancelArticleItem:
- err = DoCancelArticle(wind);
- break;
- }
- break;
- }
-
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Close
-
- Close an article window.
-
- Entry: wind = pointer to article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr Close (WindowPtr wind)
- {
- TWindow **info;
-
- info = (TWindow**)GetWRefCon(wind);
-
- RemoveChild((**info).parentWindow, wind);
-
- SaveArticleInCache(wind);
-
- if ((**info).theTE != nil) TEDispose((**info).theTE);
- MyDisposeHandle((**info).sectionBreaks);
- DisposeArrowPair((**info).sectionArrowPair);
- DisposeArrowPair((**info).nextPrevArrowPair);
- MyDisposeHandle(info);
-
- MyDisposeWindow(wind);
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Idle
-
- Handle idle time tasks for an article window.
-
- Entry: wind = pointer to article window.
-
- Exit: cursorRgn = cursor region for WaitNextEvent mouse moved events.
- ----------------------------------------------------------------------------*/
-
- static void Idle (WindowPtr wind, RgnHandle cursorRgn)
- {
- TWindow **info;
- TEHandle theTE;
- Rect r;
- Point where;
- unsigned long newsEnabled, editEnabled, specialEnabled;
- CStr255 refs;
- short selStart, selEnd;
- Rect iconRect;
-
- info = (TWindow**)GetWRefCon(wind);
- theTE = (**info).theTE;
- TEIdle(theTE);
-
- GetTextRect(wind, &r);
- InsetRect(&r, -kTextMargin, 0);
- LocalToGlobalRect(&r);
- RectRgn(cursorRgn, &r);
- if (gHaveDragMgr) SubtractTEHiliteRgn(cursorRgn, theTE);
- GetMouse(&where);
- LocalToGlobal(&where);
- if (PtInRgn(where, cursorRgn)) {
- SetCursor(&gIBeamCurs);
- } else {
- SetCursor(&qd.arrow);
- ComplementRgn(cursorRgn);
- }
-
- newsEnabled = (**info).parentWindow == nil ? kArticleNewsEnabledNoParent :
- kArticleNewsEnabled;
- editEnabled = kArticleEditEnabled;
- specialEnabled = kArticleSpecialEnabled;
- selStart = (**theTE).selStart;
- selEnd = (**theTE).selEnd;
- if (selStart >= selEnd) {
- editEnabled &= ~(kCopyMask | kEnterSelectionMask);
- } else if (selEnd > selStart + 255) {
- editEnabled &= ~kEnterSelectionMask;
- }
- if ((**theTE).teLength == 0) editEnabled &= ~(kSelectAllMask | kRot13Mask);
- if (!FindHeaderCString((**info).fullText, "References", refs, sizeof(refs)))
- specialEnabled &= ~kOpenAllReferencesMask;
- /* Following line of code disabled because it can cause repeated disk hits
- with Internet Config.
- if (!UserIsPoster((**info).fullText)) specialEnabled &= ~kCancelArticleMask;
- */
- if (!CanExtractBinaries(wind, &iconRect)) specialEnabled &= ~kExtractBinariesMask;
- if (*gFindPattern == 0) editEnabled &= ~kFindAgainMask;
- SetMenusTo(kAppleAllEnabled, kArticleFileEnabled, editEnabled,
- newsEnabled, specialEnabled, kArticleWindEnabled);
- SetEditMenuShowHideDetails(!(**info).showDetails);
- }
-
-
-
- /*----------------------------------------------------------------------------
- Help
-
- Handle help balloons for an article window.
-
- Entry: wind = pointer to article window.
- where = current mouse location in local coordinates.
- ----------------------------------------------------------------------------*/
-
- static void Help (WindowPtr wind, Point where)
- {
- TWindow **info;
- Rect r;
- Point tip = {0,0};
- short panelHeight, result, lineHeight, threadInfoWidth;
- FontInfo fontInfo;
- Boolean enabled, canExtractBinaries;
- ControlHandle hScroll;
-
- if (DoSizeBoxAndVerticalScrollBarBalloons(wind, where)) return;
- info = (TWindow**)GetWRefCon(wind);
- panelHeight = (**info).panelHeight;
- threadInfoWidth = (**info).threadInfoWidth;
- GetFontInfo(&fontInfo);
- lineHeight = fontInfo.leading + fontInfo.ascent + fontInfo.descent;
- if (lineHeight < 11) lineHeight = 11;
- SetRect(&r, 0, wind->portRect.bottom - 14, 15, wind->portRect.bottom);
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, (**info).windPosLocked ? 26 : 25);
- return;
- }
- SetRect(&r, 0, panelHeight,
- wind->portRect.right - 15, wind->portRect.bottom - 15);
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(where, &r, 27);
- return;
- }
- result = TestArrowPairHotRect((**info).nextPrevArrowPair, where, &r, &enabled);
- if (result == -1) {
- ShowHelpBalloon(tip, &r, enabled ? 28 : 29);
- return;
- } else if (result == +1) {
- ShowHelpBalloon(tip, &r, enabled ? 30 : 31);
- return;
- }
- canExtractBinaries = CanExtractBinaries(wind, &r);
- if (canExtractBinaries) {
- r.right -= 11;
- r.top += 6;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 32);
- return;
- }
- }
- r = wind->portRect;
- r.left = 5;
- r.top = 3;
- r.bottom = r.top + lineHeight;
- r.right -= 15;
- if ((**info).nextPrevArrowPair) r.right -= 12;
- if (canExtractBinaries) r.right -= 27;
- SetPt(&tip, 10, r.top + fontInfo.ascent);
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 33);
- return;
- }
- OffsetRect(&r, 0, lineHeight);
- tip.v += lineHeight;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 34);
- return;
- }
- OffsetRect(&r, 0, lineHeight);
- tip.v += lineHeight;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 35);
- return;
- }
- if ((**info).showFollowupTo) {
- OffsetRect(&r, 0, lineHeight);
- tip.v += lineHeight;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 36);
- return;
- }
- }
- if ((**info).showReplyTo) {
- OffsetRect(&r, 0, lineHeight);
- tip.v += lineHeight;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 37);
- return;
- }
- }
- OffsetRect(&r, 0, lineHeight);
- r.right = wind->portRect.right - threadInfoWidth - 15;
- tip.v += lineHeight;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 38);
- return;
- }
- if (threadInfoWidth != 0) {
- r.left = wind->portRect.right - threadInfoWidth - 15;
- r.right = wind->portRect.right;
- if (PtInRect(where, &r)) {
- tip.h = r.left + 5;
- ShowHelpBalloon(tip, &r, 39);
- }
- }
- SetPt(&tip, 0, 0);
- if ((**info).numSections > 1) {
- SetRect(&r, 16, wind->portRect.bottom - 15,
- kSectionMargin - 30, wind->portRect.bottom);
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 40);
- }
- result = TestArrowPairHotRect((**info).sectionArrowPair, where, &r, &enabled);
- if (result == -1) {
- ShowHelpBalloon(tip, &r, enabled ? 41 : 42);
- return;
- } else if (result == +1) {
- ShowHelpBalloon(tip, &r, enabled ? 43 : 44);
- return;
- }
- hScroll = (**info).hScroll;
- if (hScroll != nil) {
- r = (**hScroll).contrlRect;
- if (PtInRect(where, &r)) {
- ShowHelpBalloon(tip, &r, 45);
- return;
- }
- }
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- InitArticleDispatchTable
-
- Initialize the dispatch table for article windows.
- ----------------------------------------------------------------------------*/
-
- void InitArticleDispatchTable (void)
- {
- TDispatch *d;
-
- d = &gDispatch[kArticle];
-
- d->activate = Activate;
- d->update = Update;
- d->mouse = Mouse;
- d->draggable = Draggable;
- d->key = Key;
- d->grow = Grow;
- d->zoom = Zoom;
- d->command = Command;
- d->close = Close;
- d->idle = Idle;
- d->help = Help;
-
- gAutoScrollUPP = NewTEClickLoopProc(AutoScroll);
- gDragAttachedFileIconSendProcUPP = NewDragSendDataProc(DragAttachedFileIconSendProc);
- gScrollActionUPP = NewControlActionProc(ScrollAction);
- gScrollActionSectionUPP = NewControlActionProc(ScrollActionSection);
- }
-